+ 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;
+ }
+
+ return 0;
+}
+
+/* Calculate MUST_PRECEDE/MUST_FOLLOW bitmaps of U_NODE; which is the
+ node currently been scheduled. At the end of the calculation
+ MUST_PRECEDE/MUST_FOLLOW contains all predecessors/successors of
+ U_NODE which are (1) already scheduled in the first/last row of
+ U_NODE's scheduling window, (2) whose dependence inequality with U
+ becomes an equality when U is scheduled in this same row, and (3)
+ whose dependence latency is zero.
+
+ The first and last rows are calculated using the following parameters:
+ START/END rows - The cycles that begins/ends the traversal on the window;
+ searching for an empty cycle to schedule U_NODE.
+ STEP - The direction in which we traverse the window.
+ II - The initiation interval. */
+
+static void
+calculate_must_precede_follow (ddg_node_ptr u_node, int start, int end,
+ int step, int ii, sbitmap sched_nodes,
+ sbitmap must_precede, sbitmap must_follow)
+{
+ ddg_edge_ptr e;
+ int first_cycle_in_window, last_cycle_in_window;
+
+ gcc_assert (must_precede && must_follow);
+
+ /* Consider the following scheduling window:
+ {first_cycle_in_window, first_cycle_in_window+1, ...,
+ last_cycle_in_window}. If step is 1 then the following will be
+ the order we traverse the window: {start=first_cycle_in_window,
+ first_cycle_in_window+1, ..., end=last_cycle_in_window+1},
+ or {start=last_cycle_in_window, last_cycle_in_window-1, ...,
+ end=first_cycle_in_window-1} if step is -1. */
+ first_cycle_in_window = (step == 1) ? start : end - step;
+ last_cycle_in_window = (step == 1) ? end - step : start;
+
+ sbitmap_zero (must_precede);
+ sbitmap_zero (must_follow);
+
+ if (dump_file)
+ fprintf (dump_file, "\nmust_precede: ");
+
+ /* Instead of checking if:
+ (SMODULO (SCHED_TIME (e->src), ii) == first_row_in_window)
+ && ((SCHED_TIME (e->src) + e->latency - (e->distance * ii)) ==
+ first_cycle_in_window)
+ && e->latency == 0
+ we use the fact that latency is non-negative:
+ SCHED_TIME (e->src) - (e->distance * ii) <=
+ SCHED_TIME (e->src) + e->latency - (e->distance * ii)) <=
+ first_cycle_in_window
+ and check only if
+ SCHED_TIME (e->src) - (e->distance * ii) == first_cycle_in_window */
+ for (e = u_node->in; e != 0; e = e->next_in)
+ if (TEST_BIT (sched_nodes, e->src->cuid)
+ && ((SCHED_TIME (e->src) - (e->distance * ii)) ==
+ first_cycle_in_window))
+ {
+ if (dump_file)
+ fprintf (dump_file, "%d ", e->src->cuid);
+
+ SET_BIT (must_precede, e->src->cuid);
+ }
+
+ if (dump_file)
+ fprintf (dump_file, "\nmust_follow: ");
+
+ /* Instead of checking if:
+ (SMODULO (SCHED_TIME (e->dest), ii) == last_row_in_window)
+ && ((SCHED_TIME (e->dest) - e->latency + (e->distance * ii)) ==
+ last_cycle_in_window)
+ && e->latency == 0
+ we use the fact that latency is non-negative:
+ SCHED_TIME (e->dest) + (e->distance * ii) >=
+ SCHED_TIME (e->dest) - e->latency + (e->distance * ii)) >=
+ last_cycle_in_window
+ and check only if
+ SCHED_TIME (e->dest) + (e->distance * ii) == last_cycle_in_window */
+ for (e = u_node->out; e != 0; e = e->next_out)
+ if (TEST_BIT (sched_nodes, e->dest->cuid)
+ && ((SCHED_TIME (e->dest) + (e->distance * ii)) ==
+ last_cycle_in_window))
+ {
+ if (dump_file)
+ fprintf (dump_file, "%d ", e->dest->cuid);
+
+ SET_BIT (must_follow, e->dest->cuid);
+ }
+
+ if (dump_file)
+ fprintf (dump_file, "\n");
+}
+
+/* Return 1 if U_NODE can be scheduled in CYCLE. Use the following
+ parameters to decide if that's possible:
+ PS - The partial schedule.
+ U - The serial number of U_NODE.
+ NUM_SPLITS - The number of row splits made so far.
+ MUST_PRECEDE - The nodes that must precede U_NODE. (only valid at
+ the first row of the scheduling window)
+ MUST_FOLLOW - The nodes that must follow U_NODE. (only valid at the
+ last row of the scheduling window) */
+
+static bool
+try_scheduling_node_in_cycle (partial_schedule_ptr ps, ddg_node_ptr u_node,
+ int u, int cycle, sbitmap sched_nodes,
+ int *num_splits, sbitmap must_precede,
+ sbitmap must_follow)
+{
+ ps_insn_ptr psi;
+ bool success = 0;
+
+ verify_partial_schedule (ps, sched_nodes);
+ psi = ps_add_node_check_conflicts (ps, u_node, cycle,
+ must_precede, must_follow);
+ if (psi)
+ {
+ SCHED_TIME (u_node) = cycle;
+ SET_BIT (sched_nodes, u);
+ success = 1;
+ *num_splits = 0;
+ if (dump_file)
+ fprintf (dump_file, "Scheduled w/o split in %d\n", cycle);
+
+ }
+
+ return success;
+}
+
+/* This function implements the scheduling algorithm for SMS according to the
+ above algorithm. */
+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, num_splits = 0;
+ int flush_and_start_over = true;
+ int num_nodes = g->num_nodes;
+ int start, end, step; /* Place together into one struct? */
+ 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 (flush_and_start_over && (ii < maxii))
+ {
+
+ if (dump_file)
+ fprintf (dump_file, "Starting with ii=%d\n", ii);
+ flush_and_start_over = 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 (!NONDEBUG_INSN_P (insn))
+ {
+ RESET_BIT (tobe_scheduled, u);
+ continue;
+ }
+
+ if (JUMP_P (insn)) /* Closing branch handled later. */
+ {
+ RESET_BIT (tobe_scheduled, u);
+ continue;
+ }
+
+ if (TEST_BIT (sched_nodes, u))
+ continue;
+
+ /* Try to get non-empty scheduling window. */
+ 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);
+
+ gcc_assert ((step > 0 && start < end)
+ || (step < 0 && start > end));
+
+ calculate_must_precede_follow (u_node, start, end, step, ii,
+ sched_nodes, must_precede,
+ must_follow);
+
+ for (c = start; c != end; c += step)
+ {
+ sbitmap tmp_precede = NULL;
+ 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;
+ }
+
+ success =
+ try_scheduling_node_in_cycle (ps, u_node, u, c,
+ sched_nodes,
+ &num_splits, tmp_precede,
+ tmp_follow);
+ if (success)
+ 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++;
+ /* The scheduling window is exclusive of 'end'
+ whereas compute_split_window() expects an inclusive,
+ ordered range. */
+ if (step == 1)
+ split_row = compute_split_row (sched_nodes, start, end - 1,
+ ps->ii, u_node);
+ else
+ split_row = compute_split_row (sched_nodes, end + 1, start,
+ ps->ii, u_node);
+
+ ps_insert_empty_row (ps, split_row, sched_nodes);
+ i--; /* Go back and retry node i. */
+
+ 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. */