diff options
author | Vladimir Yanovsky <yanov@il.ibm.com> | 2007-09-03 11:50:45 +0000 |
---|---|---|
committer | Revital Eres <revitale@gcc.gnu.org> | 2007-09-03 11:50:45 +0000 |
commit | c894383202f4e66d8969287fd0a28b0ec2e1265e (patch) | |
tree | 5ad08ade11709012e9a06b72a46d4cc68126cc59 /gcc/modulo-sched.c | |
parent | d4d96a5aef412d51447c9e3632c18c6107b9315c (diff) | |
download | gcc-c894383202f4e66d8969287fd0a28b0ec2e1265e.tar.gz |
Change SMS behavior upon failure
Co-Authored-By: Ayal Zaks <zaks@il.ibm.com>
Co-Authored-By: Revital Eres <eres@il.ibm.com>
From-SVN: r128040
Diffstat (limited to 'gcc/modulo-sched.c')
-rw-r--r-- | gcc/modulo-sched.c | 487 |
1 files changed, 356 insertions, 131 deletions
diff --git a/gcc/modulo-sched.c b/gcc/modulo-sched.c index 7e9f6aa1a69..bb940a72a2b 100644 --- a/gcc/modulo-sched.c +++ b/gcc/modulo-sched.c @@ -172,13 +172,15 @@ static partial_schedule_ptr create_partial_schedule (int ii, ddg_ptr, int histor 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 void verify_partial_schedule (partial_schedule_ptr, sbitmap); 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 void ps_insert_empty_row (partial_schedule_ptr, int, sbitmap); +static int compute_split_row (sbitmap, int, int, int, ddg_node_ptr); /* This page defines constants and structures for the modulo scheduling @@ -568,23 +570,27 @@ free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces) static void normalize_sched_times (partial_schedule_ptr ps) { - int i; - ddg_ptr g = ps->g; + int row; int amount = PS_MIN_CYCLE (ps); int ii = ps->ii; + ps_insn_ptr crr_insn; - /* Don't include the closing branch assuming that it is the last node. */ - 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; - } + for (row = 0; row < ii; row++) + for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row) + { + ddg_node_ptr u = crr_insn->node; + int normalized_time = SCHED_TIME (u) - amount; + + if (dump_file) + fprintf (dump_file, "crr_insn->node=%d, crr_insn->cycle=%d,\ + min_cycle=%d\n", crr_insn->node->cuid, SCHED_TIME + (u), ps->min_cycle); + gcc_assert (SCHED_TIME (u) >= ps->min_cycle); + gcc_assert (SCHED_TIME (u) <= ps->max_cycle); + SCHED_TIME (u) = normalized_time; + SCHED_ROW (u) = normalized_time % ii; + SCHED_STAGE (u) = normalized_time / ii; + } } /* Set SCHED_COLUMN of each node according to its position in PS. */ @@ -1277,6 +1283,9 @@ sms_schedule (void) set to 0 to save compile time. */ #define DFA_HISTORY SMS_DFA_HISTORY +/* A threshold for the number of repeated unsuccessful attempts to insert + an empty row, before we flush the partial schedule and start over. */ +#define MAX_SPLIT_NUM 10 /* Given the partial schedule PS, this function calculates and returns the cycles in which we can schedule the node with the given index I. NOTE: Here we do the backtracking in SMS, in some special cases. We have @@ -1315,6 +1324,18 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, for (e = u_node->in; e != 0; e = e->next_in) { ddg_node_ptr v_node = e->src; + + if (dump_file) + { + fprintf (dump_file, "\nProcessing edge: "); + print_ddg_edge (dump_file, e); + fprintf (dump_file, + "\nScheduling %d (%d) in psp_not_empty," + " checking node %d (%d): ", u_node->cuid, + INSN_UID (u_node->insn), v_node->cuid, INSN_UID + (v_node->insn)); + } + if (TEST_BIT (sched_nodes, v_node->cuid)) { int node_st = SCHED_TIME (v_node) @@ -1329,6 +1350,11 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, start = early_start; end = MIN (end, early_start + ii); step = 1; + + if (dump_file) + fprintf (dump_file, + "\nScheduling %d (%d) in a window (%d..%d) with step %d\n", + u_node->cuid, INSN_UID (u_node->insn), start, end, step); } else if (!psp_not_empty && pss_not_empty) @@ -1339,18 +1365,45 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, for (e = u_node->out; e != 0; e = e->next_out) { ddg_node_ptr v_node = e->dest; + + if (dump_file) + { + fprintf (dump_file, "\nProcessing edge:"); + print_ddg_edge (dump_file, e); + fprintf (dump_file, + "\nScheduling %d (%d) in pss_not_empty," + " checking node %d (%d): ", u_node->cuid, + INSN_UID (u_node->insn), v_node->cuid, INSN_UID + (v_node->insn)); + } + if (TEST_BIT (sched_nodes, v_node->cuid)) { late_start = MIN (late_start, SCHED_TIME (v_node) - e->latency + (e->distance * ii)); + if (dump_file) + fprintf (dump_file, "late_start = %d;", late_start); + if (e->data_type == MEM_DEP) end = MAX (end, SCHED_TIME (v_node) - ii + 1); + if (dump_file) + fprintf (dump_file, "end = %d\n", end); + } + else if (dump_file) + fprintf (dump_file, "the node is not scheduled\n"); + } start = late_start; end = MAX (end, late_start - ii); step = -1; + + if (dump_file) + fprintf (dump_file, + "\nScheduling %d (%d) in a window (%d..%d) with step %d\n", + u_node->cuid, INSN_UID (u_node->insn), start, end, step); + } else if (psp_not_empty && pss_not_empty) @@ -1364,6 +1417,17 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, { ddg_node_ptr v_node = e->src; + if (dump_file) + { + fprintf (dump_file, "\nProcessing edge:"); + print_ddg_edge (dump_file, e); + fprintf (dump_file, + "\nScheduling %d (%d) in psp_pss_not_empty," + " checking p %d (%d): ", u_node->cuid, INSN_UID + (u_node->insn), v_node->cuid, INSN_UID + (v_node->insn)); + } + if (TEST_BIT (sched_nodes, v_node->cuid)) { early_start = MAX (early_start, @@ -1377,6 +1441,17 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, { ddg_node_ptr v_node = e->dest; + if (dump_file) + { + fprintf (dump_file, "\nProcessing edge:"); + print_ddg_edge (dump_file, e); + fprintf (dump_file, + "\nScheduling %d (%d) in psp_pss_not_empty," + " checking s %d (%d): ", u_node->cuid, INSN_UID + (u_node->insn), v_node->cuid, INSN_UID + (v_node->insn)); + } + if (TEST_BIT (sched_nodes, v_node->cuid)) { late_start = MIN (late_start, @@ -1404,8 +1479,13 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i, sbitmap_free (pss); if ((start >= end && step == 1) || (start <= end && step == -1)) + { + if (dump_file) + fprintf (dump_file, "\nEmpty window: start=%d, end=%d, step=%d\n", + start, end, step); return -1; - else + } + return 0; } @@ -1415,10 +1495,11 @@ 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 i, c, success, num_splits = 0; + int flush_and_start_over = true; int num_nodes = g->num_nodes; ddg_edge_ptr e; + ps_insn_ptr psi; int start, end, step; /* Place together into one struct? */ sbitmap sched_nodes = sbitmap_alloc (num_nodes); sbitmap must_precede = sbitmap_alloc (num_nodes); @@ -1430,19 +1511,13 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order) sbitmap_ones (tobe_scheduled); sbitmap_zero (sched_nodes); - while ((! sbitmap_equal (tobe_scheduled, sched_nodes) - || try_again_with_larger_ii ) && ii < maxii) + while (flush_and_start_over && (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); - } + flush_and_start_over = false; + sbitmap_zero (sched_nodes); for (i = 0; i < num_nodes; i++) { @@ -1466,101 +1541,271 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order) continue; /* Try to get non-empty scheduling window. */ - 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) - { - /* ??? Try backtracking instead of immediately ii++? */ - ii++; - try_again_with_larger_ii = true; - reset_partial_schedule (ps, ii); - break; - } - /* 2. Try scheduling u in window. */ - if (dump_file) - fprintf (dump_file, - "Trying to schedule node %d in (%d .. %d) step %d\n", - u, start, end, step); - - /* use must_follow & must_precede bitmaps to determine order - of nodes within the cycle. */ - sbitmap_zero (must_precede); - sbitmap_zero (must_follow); - /* TODO: We can add an insn to the must_precede or must_follow - bitmaps only if it has tight dependence to U and they - both scheduled in the same row. The current check is less - conservative and content with the fact that both U and the - insn are scheduled in the same row. */ - for (e = u_node->in; e != 0; e = e->next_in) - if (TEST_BIT (sched_nodes, e->src->cuid) - && (SMODULO (SCHED_TIME (e->src), ii) == SMODULO (start, ii))) - 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) - && (SMODULO (SCHED_TIME (e->dest), ii) == - SMODULO ((end - step), ii))) - 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) - { - /* ??? Try backtracking instead of immediately ii++? */ - ii++; - try_again_with_larger_ii = true; - reset_partial_schedule (ps, ii); - break; - } - if (unscheduled_nodes) - break; + success = 0; + if (get_sched_window (ps, nodes_order, i, sched_nodes, ii, &start, + &step, &end) == 0) + { + if (dump_file) + fprintf (dump_file, "\nTrying to schedule node %d \ + INSN = %d in (%d .. %d) step %d\n", u, (INSN_UID + (g->nodes[u].insn)), start, end, step); + /* Use must_follow & must_precede bitmaps to determine order + of nodes within the cycle. */ + + /* use must_follow & must_precede bitmaps to determine order + of nodes within the cycle. */ + sbitmap_zero (must_precede); + sbitmap_zero (must_follow); + /* TODO: We can add an insn to the must_precede or must_follow + bitmaps only if it has tight dependence to U and they + both scheduled in the same row. The current check is less + conservative and content with the fact that both U and the + insn are scheduled in the same row. */ + for (e = u_node->in; e != 0; e = e->next_in) + if (TEST_BIT (sched_nodes, e->src->cuid) + && (SMODULO (SCHED_TIME (e->src), ii) == + SMODULO (start, ii))) + 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) + && (SMODULO (SCHED_TIME (e->dest), ii) == + SMODULO ((end - step), ii))) + SET_BIT (must_follow, e->dest->cuid); + + gcc_assert ((step > 0 && start < end) + || (step < 0 && start > end)); + + for (c = start; c != end; c += step) + { + verify_partial_schedule (ps, sched_nodes); + + 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; + num_splits = 0; + if (dump_file) + fprintf (dump_file, "Scheduled w/o split in %d\n", c); + + break; + } + } + verify_partial_schedule (ps, sched_nodes); + } + if (!success) + { + int split_row; + + if (ii++ == maxii) + break; + + if (num_splits >= MAX_SPLIT_NUM) + { + num_splits = 0; + flush_and_start_over = true; + verify_partial_schedule (ps, sched_nodes); + reset_partial_schedule (ps, ii); + verify_partial_schedule (ps, sched_nodes); + break; + } + + num_splits++; + if (step == 1) + split_row = compute_split_row (sched_nodes, start, end, + ps->ii, u_node); + else + split_row = compute_split_row (sched_nodes, end, start, + ps->ii, u_node); - /* ??? If (success), check register pressure estimates. */ - } /* Continue with next node. */ - } /* While try_again_with_larger_ii. */ + ps_insert_empty_row (ps, split_row, sched_nodes); + i--; /* Go back and retry node i. */ - sbitmap_free (sched_nodes); - sbitmap_free (must_precede); - sbitmap_free (must_follow); - sbitmap_free (tobe_scheduled); + if (dump_file) + fprintf (dump_file, "num_splits=%d\n", num_splits); + } + /* ??? If (success), check register pressure estimates. */ + } /* Continue with next node. */ + } /* While flush_and_start_over. */ if (ii >= maxii) { free_partial_schedule (ps); ps = NULL; } + else + gcc_assert (sbitmap_equal (tobe_scheduled, sched_nodes)); + + sbitmap_free (sched_nodes); + sbitmap_free (must_precede); + sbitmap_free (must_follow); + sbitmap_free (tobe_scheduled); + return ps; } +/* This function inserts a new empty row into PS at the position + according to SPLITROW, keeping all already scheduled instructions + intact and updating their SCHED_TIME and cycle accordingly. */ +static void +ps_insert_empty_row (partial_schedule_ptr ps, int split_row, + sbitmap sched_nodes) +{ + ps_insn_ptr crr_insn; + ps_insn_ptr *rows_new; + int ii = ps->ii; + int new_ii = ii + 1; + int row; + + verify_partial_schedule (ps, sched_nodes); + + /* We normalize sched_time and rotate ps to have only non-negative sched + times, for simplicity of updating cycles after inserting new row. */ + split_row -= ps->min_cycle; + split_row = SMODULO (split_row, ii); + if (dump_file) + fprintf (dump_file, "split_row=%d\n", split_row); + + normalize_sched_times (ps); + rotate_partial_schedule (ps, ps->min_cycle); + + rows_new = (ps_insn_ptr *) xcalloc (new_ii, sizeof (ps_insn_ptr)); + for (row = 0; row < split_row; row++) + { + rows_new[row] = ps->rows[row]; + ps->rows[row] = NULL; + for (crr_insn = rows_new[row]; + crr_insn; crr_insn = crr_insn->next_in_row) + { + ddg_node_ptr u = crr_insn->node; + int new_time = SCHED_TIME (u) + (SCHED_TIME (u) / ii); + + SCHED_TIME (u) = new_time; + crr_insn->cycle = new_time; + SCHED_ROW (u) = new_time % new_ii; + SCHED_STAGE (u) = new_time / new_ii; + } + + } + + rows_new[split_row] = NULL; + + for (row = split_row; row < ii; row++) + { + rows_new[row + 1] = ps->rows[row]; + ps->rows[row] = NULL; + for (crr_insn = rows_new[row + 1]; + crr_insn; crr_insn = crr_insn->next_in_row) + { + ddg_node_ptr u = crr_insn->node; + int new_time = SCHED_TIME (u) + (SCHED_TIME (u) / ii) + 1; + + SCHED_TIME (u) = new_time; + crr_insn->cycle = new_time; + SCHED_ROW (u) = new_time % new_ii; + SCHED_STAGE (u) = new_time / new_ii; + } + } + + /* Updating ps. */ + ps->min_cycle = ps->min_cycle + ps->min_cycle / ii + + (SMODULO (ps->min_cycle, ii) >= split_row ? 1 : 0); + ps->max_cycle = ps->max_cycle + ps->max_cycle / ii + + (SMODULO (ps->max_cycle, ii) >= split_row ? 1 : 0); + free (ps->rows); + ps->rows = rows_new; + ps->ii = new_ii; + gcc_assert (ps->min_cycle >= 0); + + verify_partial_schedule (ps, sched_nodes); + + if (dump_file) + fprintf (dump_file, "min_cycle=%d, max_cycle=%d\n", ps->min_cycle, + ps->max_cycle); +} + +/* Given U_NODE which is the node that failed to be scheduled; LOW and + UP which are the boundaries of it's scheduling window; compute using + SCHED_NODES and II a row in the partial schedule that can be splitted + which will separate a critical predecessor from a critical successor + thereby expanding the window, and return it. */ +static int +compute_split_row (sbitmap sched_nodes, int low, int up, int ii, + ddg_node_ptr u_node) +{ + ddg_edge_ptr e; + int lower = INT_MIN, upper = INT_MAX; + ddg_node_ptr crit_pred = NULL; + ddg_node_ptr crit_succ = NULL; + int crit_cycle; + + 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) + && (low == SCHED_TIME (v_node) + e->latency - (e->distance * ii))) + if (SCHED_TIME (v_node) > lower) + { + crit_pred = v_node; + lower = SCHED_TIME (v_node); + } + } + + if (crit_pred != NULL) + { + crit_cycle = SCHED_TIME (crit_pred) + 1; + return SMODULO (crit_cycle, ii); + } + + 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) + && (up == SCHED_TIME (v_node) - e->latency + (e->distance * ii))) + if (SCHED_TIME (v_node) < upper) + { + crit_succ = v_node; + upper = SCHED_TIME (v_node); + } + } + + if (crit_succ != NULL) + { + crit_cycle = SCHED_TIME (crit_succ); + return SMODULO (crit_cycle, ii); + } + + if (dump_file) + fprintf (dump_file, "Both crit_pred and crit_succ are NULL\n"); + + return SMODULO ((low + up + 1) / 2, ii); +} + +static void +verify_partial_schedule (partial_schedule_ptr ps, sbitmap sched_nodes) +{ + int row; + ps_insn_ptr crr_insn; + + for (row = 0; row < ps->ii; row++) + for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row) + { + ddg_node_ptr u = crr_insn->node; + + gcc_assert (TEST_BIT (sched_nodes, u->cuid)); + /* ??? Test also that all nodes of sched_nodes are in ps, perhaps by + popcount (sched_nodes) == number of insns in ps. */ + gcc_assert (SCHED_TIME (u) >= ps->min_cycle); + gcc_assert (SCHED_TIME (u) <= ps->max_cycle); + } +} + /* This page implements the algorithm for ordering the nodes of a DDG for modulo scheduling, activated through the @@ -2361,26 +2606,6 @@ rotate_partial_schedule (partial_schedule_ptr ps, int start_cycle) ps->min_cycle -= start_cycle; } -/* Remove the node N from the partial schedule PS; because we restart the DFA - each time we want to check for resource conflicts; this is equivalent to - unscheduling the node N. */ -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 /* INSN_SCHEDULING */ static bool |