+ save->ready.first = ready.first;
+ save->ready.n_ready = ready.n_ready;
+ save->ready.n_debug = ready.n_debug;
+ save->ready.veclen = ready.veclen;
+ save->ready.vec = XNEWVEC (rtx, ready.veclen);
+ memcpy (save->ready.vec, ready.vec, ready.veclen * sizeof (rtx));
+
+ save->insn_queue = XNEWVEC (rtx, max_insn_queue_index + 1);
+ save->q_size = q_size;
+ for (i = 0; i <= max_insn_queue_index; i++)
+ {
+ int q = NEXT_Q_AFTER (q_ptr, i);
+ save->insn_queue[i] = copy_INSN_LIST (insn_queue[q]);
+ }
+
+ save->clock_var = clock_var;
+ save->last_clock_var = last_clock_var;
+ save->cycle_issued_insns = cycle_issued_insns;
+ save->last_scheduled_insn = last_scheduled_insn;
+ save->last_nondebug_scheduled_insn = last_nondebug_scheduled_insn;
+
+ save->sched_block = sched_block;
+
+ if (current_sched_info->save_state)
+ save->fe_saved_data = (*current_sched_info->save_state) ();
+
+ if (targetm.sched.alloc_sched_context)
+ {
+ save->be_saved_data = targetm.sched.alloc_sched_context ();
+ targetm.sched.init_sched_context (save->be_saved_data, false);
+ }
+ else
+ save->be_saved_data = NULL;
+
+ save->delay_pair = pair;
+
+ save->next = backtrack_queue;
+ backtrack_queue = save;
+
+ while (pair)
+ {
+ mark_backtrack_feeds (pair->i2, 1);
+ INSN_TICK (pair->i2) = INVALID_TICK;
+ INSN_EXACT_TICK (pair->i2) = clock_var + pair_delay (pair);
+ SHADOW_P (pair->i2) = pair->stages == 0;
+ pair = pair->next_same_i1;
+ }
+}
+
+/* Walk the ready list and all queues. If any insns have unresolved backwards
+ dependencies, these must be cancelled deps, broken by predication. Set or
+ clear (depending on SET) the DEP_CANCELLED bit in DEP_STATUS. */
+
+static void
+toggle_cancelled_flags (bool set)
+{
+ int i;
+ sd_iterator_def sd_it;
+ dep_t dep;
+
+ if (ready.n_ready > 0)
+ {
+ rtx *first = ready_lastpos (&ready);
+ for (i = 0; i < ready.n_ready; i++)
+ FOR_EACH_DEP (first[i], SD_LIST_BACK, sd_it, dep)
+ if (!DEBUG_INSN_P (DEP_PRO (dep)))
+ {
+ if (set)
+ DEP_STATUS (dep) |= DEP_CANCELLED;
+ else
+ DEP_STATUS (dep) &= ~DEP_CANCELLED;
+ }
+ }
+ for (i = 0; i <= max_insn_queue_index; i++)
+ {
+ int q = NEXT_Q_AFTER (q_ptr, i);
+ rtx link;
+ for (link = insn_queue[q]; link; link = XEXP (link, 1))
+ {
+ rtx insn = XEXP (link, 0);
+ FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
+ if (!DEBUG_INSN_P (DEP_PRO (dep)))
+ {
+ if (set)
+ DEP_STATUS (dep) |= DEP_CANCELLED;
+ else
+ DEP_STATUS (dep) &= ~DEP_CANCELLED;
+ }
+ }
+ }
+}
+
+/* Pop entries from the SCHEDULED_INSNS vector up to and including INSN.
+ Restore their dependencies to an unresolved state, and mark them as
+ queued nowhere. */
+
+static void
+unschedule_insns_until (rtx insn)
+{
+ VEC (rtx, heap) *recompute_vec;
+
+ recompute_vec = VEC_alloc (rtx, heap, 0);
+
+ /* Make two passes over the insns to be unscheduled. First, we clear out
+ dependencies and other trivial bookkeeping. */
+ for (;;)
+ {
+ rtx last;
+ sd_iterator_def sd_it;
+ dep_t dep;
+
+ last = VEC_pop (rtx, scheduled_insns);
+
+ /* This will be changed by restore_backtrack_point if the insn is in
+ any queue. */
+ QUEUE_INDEX (last) = QUEUE_NOWHERE;
+ if (last != insn)
+ INSN_TICK (last) = INVALID_TICK;
+
+ if (modulo_ii > 0 && INSN_UID (last) < modulo_iter0_max_uid)
+ modulo_insns_scheduled--;
+
+ for (sd_it = sd_iterator_start (last, SD_LIST_RES_FORW);
+ sd_iterator_cond (&sd_it, &dep);)
+ {
+ rtx con = DEP_CON (dep);
+ sd_unresolve_dep (sd_it);
+ if (!MUST_RECOMPUTE_SPEC_P (con))
+ {
+ MUST_RECOMPUTE_SPEC_P (con) = 1;
+ VEC_safe_push (rtx, heap, recompute_vec, con);
+ }
+ }
+
+ if (last == insn)
+ break;
+ }
+
+ /* A second pass, to update ready and speculation status for insns
+ depending on the unscheduled ones. The first pass must have
+ popped the scheduled_insns vector up to the point where we
+ restart scheduling, as recompute_todo_spec requires it to be
+ up-to-date. */
+ while (!VEC_empty (rtx, recompute_vec))
+ {
+ rtx con;
+
+ con = VEC_pop (rtx, recompute_vec);
+ MUST_RECOMPUTE_SPEC_P (con) = 0;
+ if (!sd_lists_empty_p (con, SD_LIST_HARD_BACK))
+ {
+ TODO_SPEC (con) = HARD_DEP;
+ INSN_TICK (con) = INVALID_TICK;
+ if (PREDICATED_PAT (con) != NULL_RTX)
+ haifa_change_pattern (con, ORIG_PAT (con));
+ }
+ else if (QUEUE_INDEX (con) != QUEUE_SCHEDULED)
+ TODO_SPEC (con) = recompute_todo_spec (con);
+ }
+ VEC_free (rtx, heap, recompute_vec);
+}
+
+/* Restore scheduler state from the topmost entry on the backtracking queue.
+ PSCHED_BLOCK_P points to the local data of schedule_block that we must
+ overwrite with the saved data.
+ The caller must already have called unschedule_insns_until. */
+
+static void
+restore_last_backtrack_point (struct sched_block_state *psched_block)
+{
+ rtx link;
+ int i;
+ struct haifa_saved_data *save = backtrack_queue;
+
+ backtrack_queue = save->next;
+
+ if (current_sched_info->restore_state)
+ (*current_sched_info->restore_state) (save->fe_saved_data);
+
+ if (targetm.sched.alloc_sched_context)
+ {
+ targetm.sched.set_sched_context (save->be_saved_data);
+ targetm.sched.free_sched_context (save->be_saved_data);
+ }
+
+ /* Clear the QUEUE_INDEX of everything in the ready list or one
+ of the queues. */
+ if (ready.n_ready > 0)
+ {
+ rtx *first = ready_lastpos (&ready);
+ for (i = 0; i < ready.n_ready; i++)
+ {
+ rtx insn = first[i];
+ QUEUE_INDEX (insn) = QUEUE_NOWHERE;
+ INSN_TICK (insn) = INVALID_TICK;
+ }
+ }
+ for (i = 0; i <= max_insn_queue_index; i++)
+ {
+ int q = NEXT_Q_AFTER (q_ptr, i);
+
+ for (link = insn_queue[q]; link; link = XEXP (link, 1))
+ {
+ rtx x = XEXP (link, 0);
+ QUEUE_INDEX (x) = QUEUE_NOWHERE;
+ INSN_TICK (x) = INVALID_TICK;
+ }
+ free_INSN_LIST_list (&insn_queue[q]);
+ }
+
+ free (ready.vec);
+ ready = save->ready;
+
+ if (ready.n_ready > 0)
+ {
+ rtx *first = ready_lastpos (&ready);
+ for (i = 0; i < ready.n_ready; i++)
+ {
+ rtx insn = first[i];
+ QUEUE_INDEX (insn) = QUEUE_READY;
+ TODO_SPEC (insn) = recompute_todo_spec (insn);
+ INSN_TICK (insn) = save->clock_var;
+ }
+ }
+
+ q_ptr = 0;
+ q_size = save->q_size;
+ for (i = 0; i <= max_insn_queue_index; i++)
+ {
+ int q = NEXT_Q_AFTER (q_ptr, i);
+
+ insn_queue[q] = save->insn_queue[q];
+
+ for (link = insn_queue[q]; link; link = XEXP (link, 1))
+ {
+ rtx x = XEXP (link, 0);
+ QUEUE_INDEX (x) = i;
+ TODO_SPEC (x) = recompute_todo_spec (x);
+ INSN_TICK (x) = save->clock_var + i;
+ }
+ }
+ free (save->insn_queue);
+
+ toggle_cancelled_flags (true);
+
+ clock_var = save->clock_var;
+ last_clock_var = save->last_clock_var;
+ cycle_issued_insns = save->cycle_issued_insns;
+ last_scheduled_insn = save->last_scheduled_insn;
+ last_nondebug_scheduled_insn = save->last_nondebug_scheduled_insn;
+
+ *psched_block = save->sched_block;
+
+ memcpy (curr_state, save->curr_state, dfa_state_size);
+ free (save->curr_state);
+
+ mark_backtrack_feeds (save->delay_pair->i2, 0);
+
+ free (save);
+
+ for (save = backtrack_queue; save; save = save->next)
+ {
+ mark_backtrack_feeds (save->delay_pair->i2, 1);
+ }
+}
+
+/* Discard all data associated with the topmost entry in the backtrack
+ queue. If RESET_TICK is false, we just want to free the data. If true,
+ we are doing this because we discovered a reason to backtrack. In the
+ latter case, also reset the INSN_TICK for the shadow insn. */
+static void
+free_topmost_backtrack_point (bool reset_tick)
+{
+ struct haifa_saved_data *save = backtrack_queue;
+ int i;
+
+ backtrack_queue = save->next;
+
+ if (reset_tick)
+ {
+ struct delay_pair *pair = save->delay_pair;
+ while (pair)
+ {
+ INSN_TICK (pair->i2) = INVALID_TICK;
+ INSN_EXACT_TICK (pair->i2) = INVALID_TICK;
+ pair = pair->next_same_i1;
+ }
+ }
+ if (targetm.sched.free_sched_context)
+ targetm.sched.free_sched_context (save->be_saved_data);
+ if (current_sched_info->restore_state)
+ free (save->fe_saved_data);
+ for (i = 0; i <= max_insn_queue_index; i++)
+ free_INSN_LIST_list (&save->insn_queue[i]);
+ free (save->insn_queue);
+ free (save->curr_state);
+ free (save->ready.vec);
+ free (save);
+}
+
+/* Free the entire backtrack queue. */
+static void
+free_backtrack_queue (void)
+{
+ while (backtrack_queue)
+ free_topmost_backtrack_point (false);
+}
+
+/* Compute INSN_TICK_ESTIMATE for INSN. PROCESSED is a bitmap of
+ instructions we've previously encountered, a set bit prevents
+ recursion. BUDGET is a limit on how far ahead we look, it is
+ reduced on recursive calls. Return true if we produced a good
+ estimate, or false if we exceeded the budget. */
+static bool
+estimate_insn_tick (bitmap processed, rtx insn, int budget)
+{
+ sd_iterator_def sd_it;
+ dep_t dep;
+ int earliest = INSN_TICK (insn);
+
+ FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
+ {
+ rtx pro = DEP_PRO (dep);
+ int t;
+
+ if (DEP_STATUS (dep) & DEP_CANCELLED)
+ continue;
+
+ if (QUEUE_INDEX (pro) == QUEUE_SCHEDULED)
+ gcc_assert (INSN_TICK (pro) + dep_cost (dep) <= INSN_TICK (insn));
+ else
+ {
+ int cost = dep_cost (dep);
+ if (cost >= budget)
+ return false;
+ if (!bitmap_bit_p (processed, INSN_LUID (pro)))
+ {
+ if (!estimate_insn_tick (processed, pro, budget - cost))
+ return false;
+ }
+ gcc_assert (INSN_TICK_ESTIMATE (pro) != INVALID_TICK);
+ t = INSN_TICK_ESTIMATE (pro) + cost;
+ if (earliest == INVALID_TICK || t > earliest)
+ earliest = t;
+ }
+ }
+ bitmap_set_bit (processed, INSN_LUID (insn));
+ INSN_TICK_ESTIMATE (insn) = earliest;
+ return true;
+}
+
+/* Examine the pair of insns in P, and estimate (optimistically, assuming
+ infinite resources) the cycle in which the delayed shadow can be issued.
+ Return the number of cycles that must pass before the real insn can be
+ issued in order to meet this constraint. */
+static int
+estimate_shadow_tick (struct delay_pair *p)
+{
+ bitmap_head processed;
+ int t;
+ bool cutoff;
+ bitmap_initialize (&processed, 0);
+
+ cutoff = !estimate_insn_tick (&processed, p->i2,
+ max_insn_queue_index + pair_delay (p));
+ bitmap_clear (&processed);
+ if (cutoff)
+ return max_insn_queue_index;
+ t = INSN_TICK_ESTIMATE (p->i2) - (clock_var + pair_delay (p) + 1);
+ if (t > 0)
+ return t;
+ return 0;
+}
+
+/* If INSN has no unresolved backwards dependencies, add it to the schedule and
+ recursively resolve all its forward dependencies. */
+static void
+resolve_dependencies (rtx insn)
+{
+ sd_iterator_def sd_it;
+ dep_t dep;
+
+ /* Don't use sd_lists_empty_p; it ignores debug insns. */
+ if (DEPS_LIST_FIRST (INSN_HARD_BACK_DEPS (insn)) != NULL
+ || DEPS_LIST_FIRST (INSN_SPEC_BACK_DEPS (insn)) != NULL)
+ return;
+
+ if (sched_verbose >= 4)
+ fprintf (sched_dump, ";;\tquickly resolving %d\n", INSN_UID (insn));
+
+ if (QUEUE_INDEX (insn) >= 0)
+ queue_remove (insn);
+
+ VEC_safe_push (rtx, heap, scheduled_insns, insn);
+
+ /* Update dependent instructions. */
+ for (sd_it = sd_iterator_start (insn, SD_LIST_FORW);
+ sd_iterator_cond (&sd_it, &dep);)
+ {
+ rtx next = DEP_CON (dep);
+
+ if (sched_verbose >= 4)
+ fprintf (sched_dump, ";;\t\tdep %d against %d\n", INSN_UID (insn),
+ INSN_UID (next));
+
+ /* Resolve the dependence between INSN and NEXT.
+ sd_resolve_dep () moves current dep to another list thus
+ advancing the iterator. */
+ sd_resolve_dep (sd_it);
+
+ if (!IS_SPECULATION_BRANCHY_CHECK_P (insn))
+ {
+ resolve_dependencies (next);
+ }
+ else
+ /* Check always has only one forward dependence (to the first insn in
+ the recovery block), therefore, this will be executed only once. */
+ {
+ gcc_assert (sd_lists_empty_p (insn, SD_LIST_FORW));
+ }
+ }
+}
+
+
+/* Return the head and tail pointers of ebb starting at BEG and ending
+ at END. */
+void
+get_ebb_head_tail (basic_block beg, basic_block end, rtx *headp, rtx *tailp)
+{
+ rtx beg_head = BB_HEAD (beg);
+ rtx beg_tail = BB_END (beg);
+ rtx end_head = BB_HEAD (end);
+ rtx end_tail = BB_END (end);
+
+ /* Don't include any notes or labels at the beginning of the BEG
+ basic block, or notes at the end of the END basic blocks. */
+
+ if (LABEL_P (beg_head))
+ beg_head = NEXT_INSN (beg_head);
+
+ while (beg_head != beg_tail)