Commit edc429ff by Revital Eres Committed by Revital Eres

Optimize stage count

From-SVN: r177235
parent 5c34e9cd
2011-08-03 Revital Eres <revital.eres@linaro.org>
* modulo-sched.c (calculate_stage_count,
calculate_must_precede_follow, get_sched_window,
try_scheduling_node_in_cycle, remove_node_from_ps): Add
declaration.
(update_node_sched_params, set_must_precede_follow, optimize_sc):
New functions.
(reset_sched_times): Call update_node_sched_params.
(sms_schedule): Call optimize_sc.
(get_sched_window): Change function arguments.
(sms_schedule_by_order): Update call to get_sched_window.
Call set_must_precede_follow.
(calculate_stage_count): Add function argument.
2011-08-02 Richard Henderson <rth@redhat.com> 2011-08-02 Richard Henderson <rth@redhat.com>
PR target/49864 PR target/49864
......
...@@ -203,7 +203,16 @@ static void generate_prolog_epilog (partial_schedule_ptr, struct loop *, ...@@ -203,7 +203,16 @@ static void generate_prolog_epilog (partial_schedule_ptr, struct loop *,
rtx, rtx); rtx, rtx);
static void duplicate_insns_of_cycles (partial_schedule_ptr, static void duplicate_insns_of_cycles (partial_schedule_ptr,
int, int, int, rtx); int, int, int, rtx);
static int calculate_stage_count (partial_schedule_ptr ps); static int calculate_stage_count (partial_schedule_ptr, int);
static void calculate_must_precede_follow (ddg_node_ptr, int, int,
int, int, sbitmap, sbitmap, sbitmap);
static int get_sched_window (partial_schedule_ptr, ddg_node_ptr,
sbitmap, int, int *, int *, int *);
static bool try_scheduling_node_in_cycle (partial_schedule_ptr, ddg_node_ptr,
int, int, sbitmap, int *, sbitmap,
sbitmap);
static bool remove_node_from_ps (partial_schedule_ptr, ps_insn_ptr);
#define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap) #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_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
#define SCHED_FIRST_REG_MOVE(x) \ #define SCHED_FIRST_REG_MOVE(x) \
...@@ -576,6 +585,36 @@ free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces) ...@@ -576,6 +585,36 @@ free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces)
} }
} }
/* Update the sched_params (time, row and stage) for node U using the II,
the CYCLE of U and MIN_CYCLE.
We're not simply taking the following
SCHED_STAGE (u) = CALC_STAGE_COUNT (SCHED_TIME (u), min_cycle, ii);
because the stages may not be aligned on cycle 0. */
static void
update_node_sched_params (ddg_node_ptr u, int ii, int cycle, int min_cycle)
{
int sc_until_cycle_zero;
int stage;
SCHED_TIME (u) = cycle;
SCHED_ROW (u) = SMODULO (cycle, ii);
/* The calculation of stage count is done adding the number
of stages before cycle zero and after cycle zero. */
sc_until_cycle_zero = CALC_STAGE_COUNT (-1, min_cycle, ii);
if (SCHED_TIME (u) < 0)
{
stage = CALC_STAGE_COUNT (-1, SCHED_TIME (u), ii);
SCHED_STAGE (u) = sc_until_cycle_zero - stage;
}
else
{
stage = CALC_STAGE_COUNT (SCHED_TIME (u), 0, ii);
SCHED_STAGE (u) = sc_until_cycle_zero + stage - 1;
}
}
/* Bump the SCHED_TIMEs of all nodes by AMOUNT. Set the values of /* Bump the SCHED_TIMEs of all nodes by AMOUNT. Set the values of
SCHED_ROW and SCHED_STAGE. Instruction scheduled on cycle AMOUNT SCHED_ROW and SCHED_STAGE. Instruction scheduled on cycle AMOUNT
will move to cycle zero. */ will move to cycle zero. */
...@@ -592,7 +631,6 @@ reset_sched_times (partial_schedule_ptr ps, int amount) ...@@ -592,7 +631,6 @@ reset_sched_times (partial_schedule_ptr ps, int amount)
ddg_node_ptr u = crr_insn->node; ddg_node_ptr u = crr_insn->node;
int normalized_time = SCHED_TIME (u) - amount; int normalized_time = SCHED_TIME (u) - amount;
int new_min_cycle = PS_MIN_CYCLE (ps) - amount; int new_min_cycle = PS_MIN_CYCLE (ps) - amount;
int sc_until_cycle_zero, stage;
if (dump_file) if (dump_file)
{ {
...@@ -608,23 +646,9 @@ reset_sched_times (partial_schedule_ptr ps, int amount) ...@@ -608,23 +646,9 @@ reset_sched_times (partial_schedule_ptr ps, int amount)
gcc_assert (SCHED_TIME (u) >= ps->min_cycle); gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
gcc_assert (SCHED_TIME (u) <= ps->max_cycle); gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
SCHED_TIME (u) = normalized_time;
SCHED_ROW (u) = SMODULO (normalized_time, ii); crr_insn->cycle = normalized_time;
update_node_sched_params (u, ii, normalized_time, new_min_cycle);
/* The calculation of stage count is done adding the number
of stages before cycle zero and after cycle zero. */
sc_until_cycle_zero = CALC_STAGE_COUNT (-1, new_min_cycle, ii);
if (SCHED_TIME (u) < 0)
{
stage = CALC_STAGE_COUNT (-1, SCHED_TIME (u), ii);
SCHED_STAGE (u) = sc_until_cycle_zero - stage;
}
else
{
stage = CALC_STAGE_COUNT (SCHED_TIME (u), 0, ii);
SCHED_STAGE (u) = sc_until_cycle_zero + stage - 1;
}
} }
} }
...@@ -661,6 +685,206 @@ permute_partial_schedule (partial_schedule_ptr ps, rtx last) ...@@ -661,6 +685,206 @@ permute_partial_schedule (partial_schedule_ptr ps, rtx last)
PREV_INSN (last)); PREV_INSN (last));
} }
/* Set bitmaps TMP_FOLLOW and TMP_PRECEDE to MUST_FOLLOW and MUST_PRECEDE
respectively only if cycle C falls on the border of the scheduling
window boundaries marked by START and END cycles. STEP is the
direction of the window. */
static inline void
set_must_precede_follow (sbitmap *tmp_follow, sbitmap must_follow,
sbitmap *tmp_precede, sbitmap must_precede, int c,
int start, int end, int step)
{
*tmp_precede = NULL;
*tmp_follow = NULL;
if (c == start)
{
if (step == 1)
*tmp_precede = must_precede;
else /* step == -1. */
*tmp_follow = must_follow;
}
if (c == end - step)
{
if (step == 1)
*tmp_follow = must_follow;
else /* step == -1. */
*tmp_precede = must_precede;
}
}
/* Return True if the branch can be moved to row ii-1 while
normalizing the partial schedule PS to start from cycle zero and thus
optimize the SC. Otherwise return False. */
static bool
optimize_sc (partial_schedule_ptr ps, ddg_ptr g)
{
int amount = PS_MIN_CYCLE (ps);
sbitmap sched_nodes = sbitmap_alloc (g->num_nodes);
int start, end, step;
int ii = ps->ii;
bool ok = false;
int stage_count, stage_count_curr;
/* Compare the SC after normalization and SC after bringing the branch
to row ii-1. If they are equal just bail out. */
stage_count = calculate_stage_count (ps, amount);
stage_count_curr =
calculate_stage_count (ps, SCHED_TIME (g->closing_branch) - (ii - 1));
if (stage_count == stage_count_curr)
{
if (dump_file)
fprintf (dump_file, "SMS SC already optimized.\n");
ok = false;
goto clear;
}
if (dump_file)
{
fprintf (dump_file, "SMS Trying to optimize branch location\n");
fprintf (dump_file, "SMS partial schedule before trial:\n");
print_partial_schedule (ps, dump_file);
}
/* First, normalize the partial scheduling. */
reset_sched_times (ps, amount);
rotate_partial_schedule (ps, amount);
if (dump_file)
{
fprintf (dump_file,
"SMS partial schedule after normalization (ii, %d, SC %d):\n",
ii, stage_count);
print_partial_schedule (ps, dump_file);
}
if (SMODULO (SCHED_TIME (g->closing_branch), ii) == ii - 1)
{
ok = true;
goto clear;
}
sbitmap_ones (sched_nodes);
/* Calculate the new placement of the branch. It should be in row
ii-1 and fall into it's scheduling window. */
if (get_sched_window (ps, g->closing_branch, sched_nodes, ii, &start,
&step, &end) == 0)
{
bool success;
ps_insn_ptr next_ps_i;
int branch_cycle = SCHED_TIME (g->closing_branch);
int row = SMODULO (branch_cycle, ps->ii);
int num_splits = 0;
sbitmap must_precede, must_follow, tmp_precede, tmp_follow;
int c;
if (dump_file)
fprintf (dump_file, "\nTrying to schedule node %d "
"INSN = %d in (%d .. %d) step %d\n",
g->closing_branch->cuid,
(INSN_UID (g->closing_branch->insn)), start, end, step);
gcc_assert ((step > 0 && start < end) || (step < 0 && start > end));
if (step == 1)
{
c = start + ii - SMODULO (start, ii) - 1;
gcc_assert (c >= start);
if (c >= end)
{
ok = false;
if (dump_file)
fprintf (dump_file,
"SMS failed to schedule branch at cycle: %d\n", c);
goto clear;
}
}
else
{
c = start - SMODULO (start, ii) - 1;
gcc_assert (c <= start);
if (c <= end)
{
if (dump_file)
fprintf (dump_file,
"SMS failed to schedule branch at cycle: %d\n", c);
ok = false;
goto clear;
}
}
must_precede = sbitmap_alloc (g->num_nodes);
must_follow = sbitmap_alloc (g->num_nodes);
/* Try to schedule the branch is it's new cycle. */
calculate_must_precede_follow (g->closing_branch, start, end,
step, ii, sched_nodes,
must_precede, must_follow);
set_must_precede_follow (&tmp_follow, must_follow, &tmp_precede,
must_precede, c, start, end, step);
/* Find the element in the partial schedule related to the closing
branch so we can remove it from it's current cycle. */
for (next_ps_i = ps->rows[row];
next_ps_i; next_ps_i = next_ps_i->next_in_row)
if (next_ps_i->node->cuid == g->closing_branch->cuid)
break;
gcc_assert (next_ps_i);
gcc_assert (remove_node_from_ps (ps, next_ps_i));
success =
try_scheduling_node_in_cycle (ps, g->closing_branch,
g->closing_branch->cuid, c,
sched_nodes, &num_splits,
tmp_precede, tmp_follow);
gcc_assert (num_splits == 0);
if (!success)
{
if (dump_file)
fprintf (dump_file,
"SMS failed to schedule branch at cycle: %d, "
"bringing it back to cycle %d\n", c, branch_cycle);
/* The branch was failed to be placed in row ii - 1.
Put it back in it's original place in the partial
schedualing. */
set_must_precede_follow (&tmp_follow, must_follow, &tmp_precede,
must_precede, branch_cycle, start, end,
step);
success =
try_scheduling_node_in_cycle (ps, g->closing_branch,
g->closing_branch->cuid,
branch_cycle, sched_nodes,
&num_splits, tmp_precede,
tmp_follow);
gcc_assert (success && (num_splits == 0));
ok = false;
}
else
{
/* The branch is placed in row ii - 1. */
if (dump_file)
fprintf (dump_file,
"SMS success in moving branch to cycle %d\n", c);
update_node_sched_params (g->closing_branch, ii, c,
PS_MIN_CYCLE (ps));
ok = true;
}
free (must_precede);
free (must_follow);
}
clear:
free (sched_nodes);
return ok;
}
static void static void
duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage, duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
int to_stage, int for_prolog, rtx count_reg) int to_stage, int for_prolog, rtx count_reg)
...@@ -1116,6 +1340,7 @@ sms_schedule (void) ...@@ -1116,6 +1340,7 @@ sms_schedule (void)
int mii, rec_mii; int mii, rec_mii;
unsigned stage_count = 0; unsigned stage_count = 0;
HOST_WIDEST_INT loop_count = 0; HOST_WIDEST_INT loop_count = 0;
bool opt_sc_p = false;
if (! (g = g_arr[loop->num])) if (! (g = g_arr[loop->num]))
continue; continue;
...@@ -1197,14 +1422,32 @@ sms_schedule (void) ...@@ -1197,14 +1422,32 @@ sms_schedule (void)
set_node_sched_params (g); set_node_sched_params (g);
ps = sms_schedule_by_order (g, mii, maxii, node_order); ps = sms_schedule_by_order (g, mii, maxii, node_order);
if (ps) if (ps)
{ {
stage_count = calculate_stage_count (ps); /* Try to achieve optimized SC by normalizing the partial
gcc_assert(stage_count >= 1); schedule (having the cycles start from cycle zero).
PS_STAGE_COUNT(ps) = stage_count; The branch location must be placed in row ii-1 in the
} final scheduling. If failed, shift all instructions to
position the branch in row ii-1. */
opt_sc_p = optimize_sc (ps, g);
if (opt_sc_p)
stage_count = calculate_stage_count (ps, 0);
else
{
/* Bring the branch to cycle ii-1. */
int amount = SCHED_TIME (g->closing_branch) - (ps->ii - 1);
if (dump_file)
fprintf (dump_file, "SMS schedule branch at cycle ii-1\n");
stage_count = calculate_stage_count (ps, amount);
}
gcc_assert (stage_count >= 1);
PS_STAGE_COUNT (ps) = stage_count;
}
/* The default value of PARAM_SMS_MIN_SC is 2 as stage count of /* The default value of PARAM_SMS_MIN_SC is 2 as stage count of
1 means that there is no interleaving between iterations thus 1 means that there is no interleaving between iterations thus
we let the scheduling passes do the job in this case. */ we let the scheduling passes do the job in this case. */
...@@ -1225,12 +1468,16 @@ sms_schedule (void) ...@@ -1225,12 +1468,16 @@ sms_schedule (void)
else else
{ {
struct undo_replace_buff_elem *reg_move_replaces; struct undo_replace_buff_elem *reg_move_replaces;
int amount = SCHED_TIME (g->closing_branch) + 1;
if (!opt_sc_p)
{
/* Rotate the partial schedule to have the branch in row ii-1. */
int amount = SCHED_TIME (g->closing_branch) - (ps->ii - 1);
reset_sched_times (ps, amount);
rotate_partial_schedule (ps, amount);
}
/* Set the stage boundaries. The closing_branch was scheduled
and should appear in the last (ii-1) row. */
reset_sched_times (ps, amount);
rotate_partial_schedule (ps, amount);
set_columns_for_ps (ps); set_columns_for_ps (ps);
canon_loop (loop); canon_loop (loop);
...@@ -1382,13 +1629,11 @@ sms_schedule (void) ...@@ -1382,13 +1629,11 @@ sms_schedule (void)
scheduling window is empty and zero otherwise. */ scheduling window is empty and zero otherwise. */
static int static int
get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, get_sched_window (partial_schedule_ptr ps, ddg_node_ptr u_node,
sbitmap sched_nodes, int ii, int *start_p, int *step_p, int *end_p) sbitmap sched_nodes, int ii, int *start_p, int *step_p, int *end_p)
{ {
int start, step, end; int start, step, end;
ddg_edge_ptr e; 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 psp = sbitmap_alloc (ps->g->num_nodes);
sbitmap pss = 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_preds = NODE_PREDECESSORS (u_node);
...@@ -1800,7 +2045,7 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order) ...@@ -1800,7 +2045,7 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
/* Try to get non-empty scheduling window. */ /* Try to get non-empty scheduling window. */
success = 0; success = 0;
if (get_sched_window (ps, nodes_order, i, sched_nodes, ii, &start, if (get_sched_window (ps, u_node, sched_nodes, ii, &start,
&step, &end) == 0) &step, &end) == 0)
{ {
if (dump_file) if (dump_file)
...@@ -1817,24 +2062,11 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order) ...@@ -1817,24 +2062,11 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
for (c = start; c != end; c += step) for (c = start; c != end; c += step)
{ {
sbitmap tmp_precede = NULL; sbitmap tmp_precede, tmp_follow;
sbitmap tmp_follow = NULL;
if (c == start)
{
if (step == 1)
tmp_precede = must_precede;
else /* step == -1. */
tmp_follow = must_follow;
}
if (c == end - step)
{
if (step == 1)
tmp_follow = must_follow;
else /* step == -1. */
tmp_precede = must_precede;
}
set_must_precede_follow (&tmp_follow, must_follow,
&tmp_precede, must_precede,
c, start, end, step);
success = success =
try_scheduling_node_in_cycle (ps, u_node, u, c, try_scheduling_node_in_cycle (ps, u_node, u, c,
sched_nodes, sched_nodes,
...@@ -2899,12 +3131,10 @@ ps_add_node_check_conflicts (partial_schedule_ptr ps, ddg_node_ptr n, ...@@ -2899,12 +3131,10 @@ ps_add_node_check_conflicts (partial_schedule_ptr ps, ddg_node_ptr n,
} }
/* Calculate the stage count of the partial schedule PS. The calculation /* Calculate the stage count of the partial schedule PS. The calculation
takes into account the rotation to bring the closing branch to row takes into account the rotation amount passed in ROTATION_AMOUNT. */
ii-1. */
int int
calculate_stage_count (partial_schedule_ptr ps) calculate_stage_count (partial_schedule_ptr ps, int rotation_amount)
{ {
int rotation_amount = (SCHED_TIME (ps->g->closing_branch)) + 1;
int new_min_cycle = PS_MIN_CYCLE (ps) - rotation_amount; int new_min_cycle = PS_MIN_CYCLE (ps) - rotation_amount;
int new_max_cycle = PS_MAX_CYCLE (ps) - rotation_amount; int new_max_cycle = PS_MAX_CYCLE (ps) - rotation_amount;
int stage_count = CALC_STAGE_COUNT (-1, new_min_cycle, ps->ii); int stage_count = CALC_STAGE_COUNT (-1, new_min_cycle, ps->ii);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment