#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"
#include "timevar.h"
#include "tree-pass.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)
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;
};
struct undo_replace_buff_elem
{
rtx insn;
rtx orig_reg;
rtx new_reg;
struct undo_replace_buff_elem *next;
};
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 int kernel_number_of_cycles (rtx first_insn, rtx last_insn);
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 bool ps_unschedule_node (partial_schedule_ptr, ddg_node_ptr );
static int issue_rate;
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 *);
static void permute_partial_schedule (partial_schedule_ptr ps, rtx last);
static void generate_prolog_epilog (partial_schedule_ptr ,struct loop * loop, rtx);
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 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,
NULL,
compute_jump_reg_dependencies,
NULL, NULL,
NULL, NULL,
0, 0, 0,
NULL, NULL, NULL, NULL, NULL,
#ifdef ENABLE_CHECKING
NULL,
#endif
0
};
static rtx
doloop_register_get (rtx insn ATTRIBUTE_UNUSED)
{
#ifdef HAVE_doloop_end
rtx pattern, reg, condition;
if (! JUMP_P (insn))
return NULL_RTX;
pattern = PATTERN (insn);
condition = doloop_condition_get (pattern);
if (! condition)
return NULL_RTX;
if (REG_P (XEXP (condition, 0)))
reg = XEXP (condition, 0);
else if (GET_CODE (XEXP (condition, 0)) == PLUS
&& REG_P (XEXP (XEXP (condition, 0), 0)))
reg = XEXP (XEXP (condition, 0), 0);
else
gcc_unreachable ();
return reg;
#else
return NULL_RTX;
#endif
}
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_ebb_head_tail (pre_header, pre_header, &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 * file, int num_nodes)
{
int i;
if (! 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 (file, "Node %d:\n", i);
fprintf (file, " asap = %d:\n", nsp->asap);
fprintf (file, " time = %d:\n", nsp->time);
fprintf (file, " nreg_moves = %d:\n", nsp->nreg_moves);
for (j = 0; j < nsp->nreg_moves; j++)
{
fprintf (file, " reg_move = ");
print_rtl_single (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 struct undo_replace_buff_elem *
generate_reg_moves (partial_schedule_ptr ps)
{
ddg_ptr g = ps->g;
int ii = ps->ii;
int i;
struct undo_replace_buff_elem *reg_move_replaces = NULL;
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++)
{
unsigned int i_use = 0;
rtx new_reg = gen_reg_rtx (GET_MODE (prev_reg));
rtx reg_move = gen_move_insn (new_reg, prev_reg);
sbitmap_iterator sbi;
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, sbi)
{
struct undo_replace_buff_elem *rep;
rep = (struct undo_replace_buff_elem *)
xcalloc (1, sizeof (struct undo_replace_buff_elem));
rep->insn = g->nodes[i_use].insn;
rep->orig_reg = old_reg;
rep->new_reg = new_reg;
if (! reg_move_replaces)
reg_move_replaces = rep;
else
{
rep->next = reg_move_replaces;
reg_move_replaces = rep;
}
replace_rtx (g->nodes[i_use].insn, old_reg, new_reg);
}
prev_reg = new_reg;
}
sbitmap_vector_free (uses_of_defs);
}
return reg_move_replaces;
}
static void
undo_generate_reg_moves (partial_schedule_ptr ps,
struct undo_replace_buff_elem *reg_move_replaces)
{
int i,j;
for (i = 0; i < ps->g->num_nodes; i++)
{
ddg_node_ptr u = &ps->g->nodes[i];
rtx prev;
rtx crr = SCHED_FIRST_REG_MOVE (u);
for (j = 0; j < SCHED_NREG_MOVES (u); j++)
{
prev = PREV_INSN (crr);
delete_insn (crr);
crr = prev;
}
SCHED_FIRST_REG_MOVE (u) = NULL_RTX;
}
while (reg_move_replaces)
{
struct undo_replace_buff_elem *rep = reg_move_replaces;
reg_move_replaces = reg_move_replaces->next;
replace_rtx (rep->insn, rep->new_reg, rep->orig_reg);
}
}
static void
free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces)
{
while (reg_move_replaces)
{
struct undo_replace_buff_elem *rep = reg_move_replaces;
reg_move_replaces = reg_move_replaces->next;
free (rep);
}
}
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;
gcc_assert (normalized_time >= 0);
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
undo_permute_partial_schedule (partial_schedule_ptr ps, rtx last)
{
int i;
for (i = 0 ; i < ps->g->num_nodes; i++)
if (last == ps->g->nodes[i].insn
|| last == ps->g->nodes[i].first_note)
break;
else if (PREV_INSN (last) != ps->g->nodes[i].insn)
reorder_insns_nobb (ps->g->nodes[i].first_note, ps->g->nodes[i].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, struct loop * loop, rtx count_reg)
{
int i;
int last_stage = PS_STAGE_COUNT (ps) - 1;
edge e;
start_sequence ();
if (count_reg)
emit_insn (gen_sub2_insn (count_reg, GEN_INT (last_stage)));
for (i = 0; i < last_stage; i++)
duplicate_insns_of_cycles (ps, 0, i, 1);
e = loop_preheader_edge (loop);
loop_split_edge_with(e , get_insns());
end_sequence ();
start_sequence ();
for (i = 0; i < last_stage; i++)
duplicate_insns_of_cycles (ps, i + 1, last_stage, 0);
gcc_assert (loop->single_exit);
e = loop->single_exit;
loop_split_edge_with(e , get_insns());
end_sequence ();
}
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;
}
static bool
loop_single_full_bb_p (struct loop *loop)
{
unsigned i;
basic_block *bbs = get_loop_body (loop);
for (i = 0; i < loop->num_nodes ; i++)
{
rtx head, tail;
bool empty_bb = true;
if (bbs[i] == loop->header)
continue;
get_ebb_head_tail (bbs[i], bbs[i], &head, &tail);
for (; head != NEXT_INSN (tail); head = NEXT_INSN (head))
{
if (NOTE_P (head) || LABEL_P (head)
|| (INSN_P (head) && JUMP_P (head)))
continue;
empty_bb = false;
break;
}
if (! empty_bb)
{
free (bbs);
return false;
}
}
free (bbs);
return true;
}
#define SIMPLE_SMS_LOOP_P(loop) ((loop->num_nodes < 3 ) \
&& (EDGE_COUNT (loop->latch->preds) == 1) \
&& (EDGE_COUNT (loop->latch->succs) == 1))
static bool
loop_canon_p (struct loop *loop)
{
if (loop->inner || ! loop->outer)
return false;
if (!loop->single_exit)
{
if (dump_file)
{
rtx line_note = find_line_note (BB_END (loop->header));
fprintf (dump_file, "SMS loop many exits ");
if (line_note)
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, line_note);
fprintf (dump_file, " %s %d (file, line)\n",
xloc.file, xloc.line);
}
}
return false;
}
if (! SIMPLE_SMS_LOOP_P (loop) && ! loop_single_full_bb_p (loop))
{
if (dump_file)
{
rtx line_note = find_line_note (BB_END (loop->header));
fprintf (dump_file, "SMS loop many BBs. ");
if (line_note)
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, line_note);
fprintf (dump_file, " %s %d (file, line)\n",
xloc.file, xloc.line);
}
}
return false;
}
return true;
}
static void
canon_loop (struct loop *loop)
{
edge e;
edge_iterator i;
FOR_EACH_EDGE (e, i, EXIT_BLOCK_PTR->preds)
if ((e->flags & EDGE_FALLTHRU) && (EDGE_COUNT (e->src->succs) > 1))
loop_split_edge_with (e, NULL_RTX);
if (loop->latch == loop->header
|| EDGE_COUNT (loop->latch->succs) > 1)
{
FOR_EACH_EDGE (e, i, loop->header->preds)
if (e->src == loop->latch)
break;
loop_split_edge_with (e, NULL_RTX);
}
}
static void
sms_schedule (void)
{
static int passes = 0;
rtx insn;
ddg_ptr *g_arr, g;
int * node_order;
int maxii;
unsigned i,num_loops;
partial_schedule_ptr ps;
struct df *df;
struct loops *loops;
basic_block bb = NULL;
struct loop * nloop;
basic_block condition_bb = NULL;
edge latch_edge;
gcov_type trip_count = 0;
loops = loop_optimizer_init (LOOPS_HAVE_PREHEADERS
| LOOPS_HAVE_MARKED_SINGLE_EXITS);
if (!loops)
return;
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 ();
df = df_init (DF_HARD_REGS | DF_EQUIV_NOTES | DF_SUBREGS);
df_rd_add_problem (df, 0);
df_ru_add_problem (df, 0);
df_chain_add_problem (df, DF_DU_CHAIN | DF_UD_CHAIN);
df_analyze (df);
if (dump_file)
df_dump (df, dump_file);
g_arr = XCNEWVEC (ddg_ptr, loops->num);
for (i = 0; i < loops->num; i++)
{
rtx head, tail;
rtx count_reg;
struct loop *loop = loops->parray[i];
if ((passes++ > MAX_SMS_LOOP_NUMBER) && (MAX_SMS_LOOP_NUMBER != -1))
{
if (dump_file)
fprintf (dump_file, "SMS reached MAX_PASSES... \n");
break;
}
if (! loop_canon_p (loop))
continue;
if (! loop_single_full_bb_p (loop))
continue;
bb = loop->header;
get_ebb_head_tail (bb, bb, &head, &tail);
latch_edge = loop_latch_edge (loop);
gcc_assert (loop->single_exit);
if (loop->single_exit->count)
trip_count = latch_edge->count / loop->single_exit->count;
if ( latch_edge->count
&& (latch_edge->count < loop->single_exit->count * SMS_LOOP_AVERAGE_COUNT_THRESHOLD))
{
if (dump_file)
{
rtx line_note = find_line_note (tail);
if (line_note)
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, line_note);
fprintf (dump_file, "SMS bb %s %d (file, line)\n",
xloc.file, xloc.line);
}
fprintf (dump_file, "SMS single-bb-loop\n");
if (profile_info && flag_branch_probabilities)
{
fprintf (dump_file, "SMS loop-count ");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) bb->count);
fprintf (dump_file, "\n");
fprintf (dump_file, "SMS trip-count ");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) trip_count);
fprintf (dump_file, "\n");
fprintf (dump_file, "SMS profile-sum-max ");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) profile_info->sum_max);
fprintf (dump_file, "\n");
}
}
continue;
}
if ( !(count_reg = doloop_register_get (tail)))
continue;
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 (dump_file)
{
if (CALL_P (insn))
fprintf (dump_file, "SMS loop-with-call\n");
else if (BARRIER_P (insn))
fprintf (dump_file, "SMS loop-with-barrier\n");
else
fprintf (dump_file, "SMS loop-with-not-single-set\n");
print_rtl_single (dump_file, insn);
}
continue;
}
if (! (g = create_ddg (bb, df, 0)))
{
if (dump_file)
fprintf (dump_file, "SMS doloop\n");
continue;
}
g_arr[i] = g;
}
df_finish (df);
df = NULL;
num_loops = loops->num;
for (i = 0; i < num_loops; i++)
{
rtx head, tail;
rtx count_reg, count_init;
int mii, rec_mii;
unsigned stage_count = 0;
HOST_WIDEST_INT loop_count = 0;
struct loop *loop = loops->parray[i];
if (! (g = g_arr[i]))
continue;
if (dump_file)
print_ddg (dump_file, g);
get_ebb_head_tail (loop->header, loop->header, &head, &tail);
latch_edge = loop_latch_edge (loop);
gcc_assert (loop->single_exit);
if (loop->single_exit->count)
trip_count = latch_edge->count / loop->single_exit->count;
if (dump_file)
{
rtx line_note = find_line_note (tail);
if (line_note)
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, line_note);
fprintf (dump_file, "SMS bb %s %d (file, line)\n",
xloc.file, xloc.line);
}
fprintf (dump_file, "SMS single-bb-loop\n");
if (profile_info && flag_branch_probabilities)
{
fprintf (dump_file, "SMS loop-count ");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) bb->count);
fprintf (dump_file, "\n");
fprintf (dump_file, "SMS profile-sum-max ");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) profile_info->sum_max);
fprintf (dump_file, "\n");
}
fprintf (dump_file, "SMS doloop\n");
fprintf (dump_file, "SMS built-ddg %d\n", g->num_nodes);
fprintf (dump_file, "SMS num-loads %d\n", g->num_loads);
fprintf (dump_file, "SMS num-stores %d\n", g->num_stores);
}
count_init = NULL_RTX;
if ((count_reg = doloop_register_get (tail)))
{
basic_block pre_header;
pre_header = loop_preheader_edge (loop)->src;
count_init = const_iteration_count (count_reg, pre_header,
&loop_count);
}
gcc_assert (count_reg);
if (dump_file && count_init)
{
fprintf (dump_file, "SMS const-doloop ");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
loop_count);
fprintf (dump_file, "\n");
}
node_order = XNEWVEC (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 (dump_file)
fprintf (dump_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);
if (ps)
stage_count = PS_STAGE_COUNT (ps);
if (stage_count < 1
|| (count_init && (loop_count <= stage_count))
|| (flag_branch_probabilities && (trip_count <= stage_count)))
{
if (dump_file)
{
fprintf (dump_file, "SMS failed... \n");
fprintf (dump_file, "SMS sched-failed (stage-count=%d, loop-count=", stage_count);
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, loop_count);
fprintf (dump_file, ", trip-count=");
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, trip_count);
fprintf (dump_file, ")\n");
}
continue;
}
else
{
int orig_cycles = kernel_number_of_cycles (BB_HEAD (g->bb), BB_END (g->bb));
int new_cycles;
struct undo_replace_buff_elem *reg_move_replaces;
if (dump_file)
{
fprintf (dump_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);
}
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);
reg_move_replaces = generate_reg_moves (ps);
new_cycles = kernel_number_of_cycles (BB_HEAD (g->bb), BB_END (g->bb));
undo_permute_partial_schedule (ps, g->closing_branch->first_note);
if (reg_move_replaces)
undo_generate_reg_moves (ps, reg_move_replaces);
if ( new_cycles >= orig_cycles)
{
if (dump_file)
fprintf (dump_file, "Undoing SMS because it is not profitable.\n");
}
else
{
canon_loop (loop);
if (count_reg && ! count_init)
{
rtx comp_rtx = gen_rtx_fmt_ee (GT, VOIDmode, count_reg,
GEN_INT(stage_count));
nloop = loop_version (loops, loop, comp_rtx, &condition_bb,
true);
}
if (count_reg && count_init)
SET_SRC (single_set (count_init)) = GEN_INT (loop_count
- stage_count + 1);
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;
reg_move_replaces = generate_reg_moves (ps);
if (dump_file)
print_node_sched_params (dump_file, g->num_nodes);
if (count_reg && !count_init)
generate_prolog_epilog (ps, loop, count_reg);
else
generate_prolog_epilog (ps, loop, NULL_RTX);
}
free_undo_replace_buff (reg_move_replaces);
}
free_partial_schedule (ps);
free (node_sched_params);
free (node_order);
free_ddg (g);
}
free (g_arr);
sched_finish ();
loop_optimizer_finalize (loops);
}
#define DFA_HISTORY SMS_DFA_HISTORY
static int
get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
sbitmap sched_nodes, int ii, int *start_p, int *step_p, int *end_p)
{
int start, step, end;
ddg_edge_ptr e;
int u = nodes_order [i];
ddg_node_ptr u_node = &ps->g->nodes[u];
sbitmap psp = sbitmap_alloc (ps->g->num_nodes);
sbitmap pss = sbitmap_alloc (ps->g->num_nodes);
sbitmap u_node_preds = NODE_PREDECESSORS (u_node);
sbitmap u_node_succs = NODE_SUCCESSORS (u_node);
int psp_not_empty;
int pss_not_empty;
sbitmap_zero (psp);
sbitmap_zero (pss);
psp_not_empty = sbitmap_a_and_b_cg (psp, u_node_preds, sched_nodes);
pss_not_empty = sbitmap_a_and_b_cg (pss, u_node_succs, sched_nodes);
if (psp_not_empty && !pss_not_empty)
{
int early_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))
{
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 = INT_MIN;
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;
}
*start_p = start;
*step_p = step;
*end_p = end;
sbitmap_free (psp);
sbitmap_free (pss);
if ((start >= end && step == 1) || (start <= end && step == -1))
return -1;
else
return 0;
}
static partial_schedule_ptr
sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
{
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);
sbitmap tobe_scheduled = sbitmap_alloc (num_nodes);
partial_schedule_ptr ps = create_partial_schedule (ii, g, DFA_HISTORY);
sbitmap_ones (tobe_scheduled);
sbitmap_zero (sched_nodes);
while ((! sbitmap_equal (tobe_scheduled, sched_nodes)
|| try_again_with_larger_ii ) && ii < maxii)
{
int j;
bool unscheduled_nodes = false;
if (dump_file)
fprintf(dump_file, "Starting with ii=%d\n", ii);
if (try_again_with_larger_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 = &ps->g->nodes[u];
rtx insn = u_node->insn;
if (!INSN_P (insn))
{
RESET_BIT (tobe_scheduled, u);
continue;
}
if (JUMP_P (insn))
{
RESET_BIT (tobe_scheduled, u);
continue;
}
if (TEST_BIT (sched_nodes, u))
continue;
j = i;
while (get_sched_window (ps, nodes_order, i, sched_nodes, ii, &start, &step, &end) < 0
&& j > 0)
{
unscheduled_nodes = true;
if (TEST_BIT (NODE_PREDECESSORS (u_node), nodes_order[j - 1])
|| TEST_BIT (NODE_SUCCESSORS (u_node), nodes_order[j - 1]))
{
ps_unschedule_node (ps, &ps->g->nodes[nodes_order[j - 1]]);
RESET_BIT (sched_nodes, nodes_order [j - 1]);
}
j--;
}
if (j < 0)
{
ii++;
try_again_with_larger_ii = true;
reset_partial_schedule (ps, ii);
break;
}
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;
}
if (unscheduled_nodes)
break;
}
}
sbitmap_free (sched_nodes);
sbitmap_free (must_precede);
sbitmap_free (must_follow);
sbitmap_free (tobe_scheduled);
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];
gcc_assert (u < num_nodes && u >= 0 && !TEST_BIT (tmp, u));
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)
{
unsigned int u = 0;
int max_asap = -1;
int result = -1;
sbitmap_iterator sbi;
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, u, sbi)
{
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)
{
unsigned int u = 0;
int max_hv = -1;
int min_mob = INT_MAX;
int result = -1;
sbitmap_iterator sbi;
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, u, sbi)
{
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)
{
unsigned int u = 0;
int max_dv = -1;
int min_mob = INT_MAX;
int result = -1;
sbitmap_iterator sbi;
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, u, sbi)
{
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 = XNEW (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 = XNEW (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 bool
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
kernel_number_of_cycles (rtx first_insn, rtx last_insn)
{
int cycles = 0;
rtx insn;
int can_issue_more = issue_rate;
state_reset (curr_state);
for (insn = first_insn;
insn != NULL_RTX && insn != last_insn;
insn = NEXT_INSN (insn))
{
if (! INSN_P (insn) || GET_CODE (PATTERN (insn)) == USE)
continue;
if (!can_issue_more || state_dead_lock_p (curr_state))
{
cycles ++;
advance_one_cycle ();
can_issue_more = issue_rate;
}
if (state_transition (curr_state, insn) >= 0)
{
cycles ++;
advance_one_cycle ();
can_issue_more = issue_rate;
}
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--;
}
return cycles;
}
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;
}
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;
}
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;
}
static bool
ps_unschedule_node (partial_schedule_ptr ps, ddg_node_ptr n)
{
ps_insn_ptr ps_i;
int row = SMODULO (SCHED_TIME (n), ps->ii);
if (row < 0 || row > ps->ii)
return false;
for (ps_i = ps->rows[row];
ps_i && ps_i->node != n;
ps_i = ps_i->next_in_row);
if (!ps_i)
return false;
return remove_node_from_ps (ps, ps_i);
}
#endif
static bool
gate_handle_sms (void)
{
return (optimize > 0 && flag_modulo_sched);
}
static unsigned int
rest_of_handle_sms (void)
{
#ifdef INSN_SCHEDULING
basic_block bb;
no_new_pseudos = 0;
cfg_layout_initialize (CLEANUP_UPDATE_LIFE);
sms_schedule ();
max_regno = max_reg_num ();
allocate_reg_info (max_regno, FALSE, FALSE);
update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
(PROP_DEATH_NOTES
| PROP_REG_INFO
| PROP_KILL_DEAD_CODE
| PROP_SCAN_DEAD_CODE));
no_new_pseudos = 1;
FOR_EACH_BB (bb)
if (bb->next_bb != EXIT_BLOCK_PTR)
bb->aux = bb->next_bb;
cfg_layout_finalize ();
free_dominance_info (CDI_DOMINATORS);
#endif
return 0;
}
struct tree_opt_pass pass_sms =
{
"sms",
gate_handle_sms,
rest_of_handle_sms,
NULL,
NULL,
0,
TV_SMS,
0,
0,
0,
TODO_dump_func,
TODO_dump_func |
TODO_ggc_collect,
'm'
};