/* Instruction scheduling pass.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
and currently maintained by, Jim Wilson (wilson@cygnus.com)
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.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 "dbgcnt.h"
#include "cfgloop.h"
#include "ira.h"
+#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
#ifdef INSN_SCHEDULING
N=3: rtl at abort point, control-flow, regions info.
N=5: dependences info. */
-static int sched_verbose_param = 0;
int sched_verbose = 0;
/* Debugging file. All printouts are sent to dump, which is always set,
either to stderr, or to the dump listing file (-dRS). */
FILE *sched_dump = 0;
-/* fix_sched_param() is called from toplev.c upon detection
- of the -fsched-verbose=N option. */
-
-void
-fix_sched_param (const char *param, const char *val)
-{
- if (!strcmp (param, "verbose"))
- sched_verbose_param = atoi (val);
- else
- warning (0, "fix_sched_param: unknown param: %s", param);
-}
-
-/* This is a placeholder for the scheduler parameters common
+/* This is a placeholder for the scheduler parameters common
to all schedulers. */
struct common_sched_info_def *common_sched_info;
/* The minimal value of the INSN_TICK of an instruction. */
#define MIN_TICK (-max_insn_queue_index)
-/* Issue points are used to distinguish between instructions in max_issue ().
- For now, all instructions are equally good. */
-#define ISSUE_POINTS(INSN) 1
-
/* List of important notes we must keep around. This is a pointer to the
last element in the list. */
rtx note_list;
queue or ready list.
QUEUE_READY - INSN is in ready list.
N >= 0 - INSN queued for X [where NEXT_Q_AFTER (q_ptr, X) == N] cycles. */
-
+
#define QUEUE_INDEX(INSN) (HID (INSN)->queue_index)
/* The following variable value refers for all current and future
static int haifa_luid_for_non_insn (rtx x);
/* Haifa version of sched_info hooks common to all headers. */
-const struct common_sched_info_def haifa_common_sched_info =
+const struct common_sched_info_def haifa_common_sched_info =
{
NULL, /* fix_recovery_cfg */
NULL, /* add_block */
static void ready_add (struct ready_list *, rtx, bool);
static rtx ready_remove_first (struct ready_list *);
+static rtx ready_remove_first_dispatch (struct ready_list *ready);
static void queue_to_ready (struct ready_list *);
static int early_queue_to_ready (state_t, struct ready_list *);
static rtx ready_remove (struct ready_list *, int);
static void ready_remove_insn (rtx);
-static int choose_ready (struct ready_list *, rtx *);
-
static void fix_inter_tick (rtx, rtx);
static int fix_tick_ready (rtx);
static void change_queue_index (rtx, int);
static void
initiate_bb_reg_pressure_info (basic_block bb)
{
- unsigned int i;
+ unsigned int i ATTRIBUTE_UNUSED;
rtx insn;
if (current_nr_blocks > 1)
FOR_BB_INSNS (bb, insn)
- if (INSN_P (insn))
+ if (NONDEBUG_INSN_P (insn))
setup_ref_regs (PATTERN (insn));
initiate_reg_pressure_info (df_get_live_in (bb));
#ifdef EH_RETURN_DATA_REGNO
for (i = 0; ; ++i)
{
unsigned int regno = EH_RETURN_DATA_REGNO (i);
-
+
if (regno == INVALID_REGNUM)
break;
if (! bitmap_bit_p (df_get_live_in (bb), regno))
save_reg_pressure (void)
{
int i;
-
+
for (i = 0; i < ira_reg_class_cover_size; i++)
saved_reg_pressure[ira_reg_class_cover[i]]
= curr_reg_pressure[ira_reg_class_cover[i]];
restore_reg_pressure (void)
{
int i;
-
+
for (i = 0; i < ira_reg_class_cover_size; i++)
curr_reg_pressure[ira_reg_class_cover[i]]
= saved_reg_pressure[ira_reg_class_cover[i]];
struct reg_use_data *next;
for (next = use->next_regno_use; next != use; next = next->next_regno_use)
- if (QUEUE_INDEX (next->insn) != QUEUE_SCHEDULED)
+ if (NONDEBUG_INSN_P (next->insn)
+ && QUEUE_INDEX (next->insn) != QUEUE_SCHEDULED)
return false;
return true;
}
else if (bypass_p (insn))
cost = insn_latency (insn, used);
}
-
+
if (targetm.sched.adjust_cost_2)
cost = targetm.sched.adjust_cost_2 (used, (int) dep_type, insn, cost,
}
else
{
- /* In sel-sched.c INSN_PRIORITY is not kept up to date.
+ /* In sel-sched.c INSN_PRIORITY is not kept up to date.
Use EXPR_PRIORITY instead. */
sel_add_to_insn_priority (insn, amount);
}
different than that of normal instructions. Instead of walking
through INSN_FORW_DEPS (check) list, we walk through
INSN_FORW_DEPS list of each instruction in the corresponding
- recovery block. */
+ recovery block. */
/* Selective scheduling does not define RECOVERY_BLOCK macro. */
rec = sel_sched_p () ? NULL : RECOVERY_BLOCK (insn);
this_priority = next_priority;
}
}
-
+
twin = PREV_INSN (twin);
}
while (twin != prev_first);
struct reg_use_data *use;
static int death[N_REG_CLASSES];
+ gcc_checking_assert (!DEBUG_INSN_P (insn));
+
excess_cost_change = 0;
for (i = 0; i < ira_reg_class_cover_size; i++)
death[ira_reg_class_cover[i]] = 0;
}
/* The insn in a schedule group should be issued the first. */
- if (flag_sched_group_heuristic &&
+ if (flag_sched_group_heuristic &&
SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2))
return SCHED_GROUP_P (tmp2) ? 1 : -1;
if (flag_sched_critical_path_heuristic && priority_val)
return priority_val;
-
+
/* Prefer speculative insn with greater dependencies weakness. */
if (flag_sched_spec_insn_heuristic && spec_info)
{
dw1 = ds_weak (ds1);
else
dw1 = NO_DEP_WEAK;
-
+
ds2 = TODO_SPEC (tmp2) & SPECULATIVE;
if (ds2)
dw2 = ds_weak (ds2);
ready_remove_first (struct ready_list *ready)
{
rtx t;
-
+
gcc_assert (ready->n_ready);
t = ready->vec[ready->first--];
ready->n_ready--;
ready_element (struct ready_list *ready, int index)
{
gcc_assert (ready->n_ready && index < ready->n_ready);
-
+
return ready->vec[ready->first - index];
}
if (sched_pressure_p)
{
for (i = 0; i < ready->n_ready; i++)
- setup_insn_reg_pressure_info (first[i]);
+ if (!DEBUG_INSN_P (first[i]))
+ setup_insn_reg_pressure_info (first[i]);
}
SCHED_SORT (first, ready->n_ready);
}
targetm.sched.dfa_pre_cycle_insn ());
state_transition (state, NULL);
-
+
if (targetm.sched.dfa_post_cycle_insn)
state_transition (state,
targetm.sched.dfa_post_cycle_insn ());
struct reg_use_data *use;
struct reg_set_data *set;
+ gcc_checking_assert (!DEBUG_INSN_P (insn));
+
for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
if (dying_use_p (use) && bitmap_bit_p (curr_reg_live, use->regno))
mark_regno_birth_or_death (use->regno, false);
max_reg_pressure[ira_reg_class_cover[i]]
= curr_reg_pressure[ira_reg_class_cover[i]];
for (insn = NEXT_INSN (after);
- insn != NULL_RTX && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (after);
+ insn != NULL_RTX && ! BARRIER_P (insn)
+ && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (after);
insn = NEXT_INSN (insn))
if (NONDEBUG_INSN_P (insn))
{
fputc ('\n', sched_dump);
}
- if (sched_pressure_p)
+ if (sched_pressure_p && !DEBUG_INSN_P (insn))
update_reg_and_insn_max_reg_pressure (insn);
/* Scheduling instruction should have all its dependencies resolved and
sd_iterator_cond (&sd_it, &dep);)
{
rtx dbg = DEP_PRO (dep);
+ struct reg_use_data *use, *next;
gcc_assert (DEBUG_INSN_P (dbg));
INSN_VAR_LOCATION_LOC (dbg) = gen_rtx_UNKNOWN_VAR_LOC ();
df_insn_rescan (dbg);
+ /* Unknown location doesn't use any registers. */
+ for (use = INSN_REG_USE_LIST (dbg); use != NULL; use = next)
+ {
+ struct reg_use_data *prev = use;
+
+ /* Remove use from the cyclic next_regno_use chain first. */
+ while (prev->next_regno_use != use)
+ prev = prev->next_regno_use;
+ prev->next_regno_use = use->next_regno_use;
+ next = use->next_insn_use;
+ free (use);
+ }
+ INSN_REG_USE_LIST (dbg) = NULL;
+
/* We delete rather than resolve these deps, otherwise we
crash in sched_free_deps(), because forward deps are
expected to be released before backward deps. */
if (INSN_TICK (insn) > clock_var)
/* INSN has been prematurely moved from the queue to the ready list.
This is possible only if following flag is set. */
- gcc_assert (flag_sched_stalled_insns);
+ gcc_assert (flag_sched_stalled_insns);
/* ??? Probably, if INSN is scheduled prematurely, we should leave
INSN_TICK untouched. This is a machine-dependent issue, actually. */
if (!IS_SPECULATION_BRANCHY_CHECK_P (insn))
{
- int effective_cost;
-
+ int effective_cost;
+
effective_cost = try_ready (next);
-
+
if (effective_cost >= 0
&& SCHED_GROUP_P (next)
&& advance < effective_cost)
forward dependencies for INSN anymore. Nevertheless they are used in
heuristics in rank_for_schedule (), early_queue_to_ready () and in
some targets (e.g. rs6000). Thus the earliest place where we *can*
- remove dependencies is after targetm.sched.md_finish () call in
+ remove dependencies is after targetm.sched.finish () call in
schedule_block (). But, on the other side, the safest place to remove
dependencies is when we are finishing scheduling entire region. As we
don't generate [many] dependencies during scheduling itself, we won't
/* Functions for handling of notes. */
-/* Insert the INSN note at the end of the notes list. */
-static void
-add_to_note_list (rtx insn, rtx *note_list_end_p)
-{
- PREV_INSN (insn) = *note_list_end_p;
- if (*note_list_end_p)
- NEXT_INSN (*note_list_end_p) = insn;
- *note_list_end_p = insn;
-}
-
/* Add note list that ends on FROM_END to the end of TO_ENDP. */
void
concat_note_lists (rtx from_end, rtx *to_endp)
{
rtx from_start;
+ /* It's easy when have nothing to concat. */
if (from_end == NULL)
- /* It's easy when have nothing to concat. */
return;
+ /* It's also easy when destination is empty. */
if (*to_endp == NULL)
- /* It's also easy when destination is empty. */
{
*to_endp = from_end;
return;
}
from_start = from_end;
- /* A note list should be traversed via PREV_INSN. */
- while (PREV_INSN (from_start) != NULL)
+ while (PREV_INSN (from_start) != NULL)
from_start = PREV_INSN (from_start);
- add_to_note_list (from_start, to_endp);
+ PREV_INSN (from_start) = *to_endp;
+ NEXT_INSN (*to_endp) = from_start;
*to_endp = from_end;
}
-/* Delete notes beginning with INSN and put them in the chain
- of notes ended by NOTE_LIST.
- Returns the insn following the notes. */
-static rtx
-unlink_other_notes (rtx insn, rtx tail)
+/* Delete notes between HEAD and TAIL and put them in the chain
+ of notes ended by NOTE_LIST. */
+void
+remove_notes (rtx head, rtx tail)
{
- rtx prev = PREV_INSN (insn);
+ rtx next_tail, insn, next;
- while (insn != tail && NOTE_NOT_BB_P (insn))
- {
- rtx next = NEXT_INSN (insn);
- basic_block bb = BLOCK_FOR_INSN (insn);
-
- /* Delete the note from its current position. */
- if (prev)
- NEXT_INSN (prev) = next;
- if (next)
- PREV_INSN (next) = prev;
+ note_list = 0;
+ if (head == tail && !INSN_P (head))
+ return;
- if (bb)
- {
- /* Basic block can begin with either LABEL or
- NOTE_INSN_BASIC_BLOCK. */
- gcc_assert (BB_HEAD (bb) != insn);
+ next_tail = NEXT_INSN (tail);
+ for (insn = head; insn != next_tail; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (!NOTE_P (insn))
+ continue;
- /* Check if we are removing last insn in the BB. */
- if (BB_END (bb) == insn)
- BB_END (bb) = prev;
- }
+ switch (NOTE_KIND (insn))
+ {
+ case NOTE_INSN_BASIC_BLOCK:
+ continue;
- /* See sched_analyze to see how these are handled. */
- if (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
- && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END)
- add_to_note_list (insn, ¬e_list);
+ case NOTE_INSN_EPILOGUE_BEG:
+ if (insn != tail)
+ {
+ remove_insn (insn);
+ add_reg_note (next, REG_SAVE_NOTE,
+ GEN_INT (NOTE_INSN_EPILOGUE_BEG));
+ break;
+ }
+ /* FALLTHRU */
- insn = next;
- }
+ default:
+ remove_insn (insn);
+
+ /* Add the note to list that ends at NOTE_LIST. */
+ PREV_INSN (insn) = note_list;
+ NEXT_INSN (insn) = NULL_RTX;
+ if (note_list)
+ NEXT_INSN (note_list) = insn;
+ note_list = insn;
+ break;
+ }
- if (insn == tail)
- {
- gcc_assert (sel_sched_p ());
- return prev;
+ gcc_assert ((sel_sched_p () || insn != tail) && insn != head);
}
-
- return insn;
}
+
/* Return the head and tail pointers of ebb starting at BEG and ending
at END. */
void
return 1;
}
-/* Delete notes between HEAD and TAIL and put them in the chain
- of notes ended by NOTE_LIST. */
-static void
-rm_other_notes (rtx head, rtx tail)
-{
- rtx next_tail;
- rtx insn;
-
- note_list = 0;
- if (head == tail && (! INSN_P (head)))
- return;
-
- next_tail = NEXT_INSN (tail);
- for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
- {
- rtx prev;
-
- /* Farm out notes, and maybe save them in NOTE_LIST.
- This is needed to keep the debugger from
- getting completely deranged. */
- if (NOTE_NOT_BB_P (insn))
- {
- prev = insn;
- insn = unlink_other_notes (insn, next_tail);
-
- gcc_assert ((sel_sched_p ()
- || prev != tail) && prev != head && insn != next_tail);
- }
- }
-}
-
-/* Same as above, but also process REG_SAVE_NOTEs of HEAD. */
-void
-remove_notes (rtx head, rtx tail)
-{
- /* rm_other_notes only removes notes which are _inside_ the
- block---that is, it won't remove notes before the first real insn
- or after the last real insn of the block. So if the first insn
- has a REG_SAVE_NOTE which would otherwise be emitted before the
- insn, it is redundant with the note before the start of the
- block, and so we have to take it out. */
- if (INSN_P (head))
- {
- rtx note;
-
- for (note = REG_NOTES (head); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
- remove_note (head, note);
- }
-
- /* Remove remaining note insns from the block, save them in
- note_list. These notes are restored at the end of
- schedule_block (). */
- rm_other_notes (head, tail);
-}
-
/* Restore-other-notes: NOTE_LIST is the end of a chain of notes
previously found among the insns. Insert them just before HEAD. */
rtx
q_ptr = NEXT_Q (q_ptr);
if (dbg_cnt (sched_insn) == false)
- {
- /* If debug counter is activated do not requeue insn next after
- last_scheduled_insn. */
- skip_insn = next_nonnote_insn (last_scheduled_insn);
- while (skip_insn && DEBUG_INSN_P (skip_insn))
- skip_insn = next_nonnote_insn (skip_insn);
- }
+ /* If debug counter is activated do not requeue insn next after
+ last_scheduled_insn. */
+ skip_insn = next_nonnote_nondebug_insn (last_scheduled_insn);
else
skip_insn = NULL_RTX;
}
/* Used by early_queue_to_ready. Determines whether it is "ok" to
- prematurely move INSN from the queue to the ready list. Currently,
- if a target defines the hook 'is_costly_dependence', this function
+ prematurely move INSN from the queue to the ready list. Currently,
+ if a target defines the hook 'is_costly_dependence', this function
uses the hook to check whether there exist any dependences which are
- considered costly by the target, between INSN and other insns that
+ considered costly by the target, between INSN and other insns that
have already been scheduled. Dependences are checked up to Y cycles
back, with default Y=1; The flag -fsched-stalled-insns-dep=Y allows
- controlling this value.
- (Other considerations could be taken into account instead (or in
+ controlling this value.
+ (Other considerations could be taken into account instead (or in
addition) depending on user flags and target hooks. */
-static bool
+static bool
ok_for_early_queue_removal (rtx insn)
{
int n_cycles;
break;
}
- if (!prev_insn)
+ if (!prev_insn)
break;
- prev_insn = PREV_INSN (prev_insn);
+ prev_insn = PREV_INSN (prev_insn);
}
}
/* Remove insns from the queue, before they become "ready" with respect
to FU latency considerations. */
-static int
+static int
early_queue_to_ready (state_t state, struct ready_list *ready)
{
rtx insn;
int insns_removed = 0;
/*
- Flag '-fsched-stalled-insns=X' determines the aggressiveness of this
- function:
+ Flag '-fsched-stalled-insns=X' determines the aggressiveness of this
+ function:
- X == 0: There is no limit on how many queued insns can be removed
+ X == 0: There is no limit on how many queued insns can be removed
prematurely. (flag_sched_stalled_insns = -1).
- X >= 1: Only X queued insns can be removed prematurely in each
+ X >= 1: Only X queued insns can be removed prematurely in each
invocation. (flag_sched_stalled_insns = X).
Otherwise: Early queue removal is disabled.
(flag_sched_stalled_insns = 0)
*/
- if (! flag_sched_stalled_insns)
+ if (! flag_sched_stalled_insns)
return 0;
for (stalls = 0; stalls <= max_insn_queue_index; stalls++)
print_rtl_single (sched_dump, insn);
memcpy (temp_state, state, dfa_state_size);
- if (recog_memoized (insn) < 0)
+ if (recog_memoized (insn) < 0)
/* non-negative to indicate that it's not ready
to avoid infinite Q->R->Q->R... */
cost = 0;
fprintf (sched_dump, "transition cost = %d\n", cost);
move_to_ready = false;
- if (cost < 0)
+ if (cost < 0)
{
move_to_ready = ok_for_early_queue_removal (insn);
if (move_to_ready == true)
q_size -= 1;
ready_add (ready, insn, false);
- if (prev_link)
+ if (prev_link)
XEXP (prev_link, 1) = next_link;
else
insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = next_link;
link = next_link;
} /* while link */
- } /* if link */
+ } /* if link */
} /* for stalls.. */
- return insns_removed;
+ return insns_removed;
}
fprintf (sched_dump, "\n");
}
-/* Search INSN for REG_SAVE_NOTE note pairs for
- NOTE_INSN_EHREGION_{BEG,END}; and convert them back into
- NOTEs. The REG_SAVE_NOTE note following first one is contains the
- saved value for NOTE_BLOCK_NUMBER which is useful for
- NOTE_INSN_EH_REGION_{BEG,END} NOTEs. */
+/* Search INSN for REG_SAVE_NOTE notes and convert them back into insn
+ NOTEs. This is used for NOTE_INSN_EPILOGUE_BEG, so that sched-ebb
+ replaces the epilogue note in the correct basic block. */
void
reemit_notes (rtx insn)
{
int jump_p = 0;
bb = BLOCK_FOR_INSN (insn);
-
+
/* BB_HEAD is either LABEL or NOTE. */
- gcc_assert (BB_HEAD (bb) != insn);
+ gcc_assert (BB_HEAD (bb) != insn);
if (BB_END (bb) == insn)
/* If this is last instruction in BB, move end marker one
&& IS_SPECULATION_BRANCHY_CHECK_P (insn))
|| (common_sched_info->sched_pass_id
== SCHED_EBB_PASS));
-
+
gcc_assert (BLOCK_FOR_INSN (PREV_INSN (insn)) == bb);
BB_END (bb) = PREV_INSN (insn);
&& (LABEL_P (note)
|| BARRIER_P (note)))
note = NEXT_INSN (note);
-
+
gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
}
else
}
df_insn_change_bb (insn, bb);
-
+
/* Update BB_END, if needed. */
if (BB_END (bb) == last)
- BB_END (bb) = insn;
+ BB_END (bb) = insn;
}
- SCHED_GROUP_P (insn) = 0;
+ SCHED_GROUP_P (insn) = 0;
}
/* Return true if scheduling INSN will finish current clock cycle. */
return false;
}
+/* Define type for target data used in multipass scheduling. */
+#ifndef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T
+# define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T int
+#endif
+typedef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T first_cycle_multipass_data_t;
+
/* The following structure describe an entry of the stack of choices. */
struct choice_entry
{
int n;
/* State after issuing the insn. */
state_t state;
+ /* Target-specific data. */
+ first_cycle_multipass_data_t target_data;
};
/* The following array is used to implement a stack of choices used in
insns is insns with the best rank (the first insn in READY). To
make this function tries different samples of ready insns. READY
is current queue `ready'. Global array READY_TRY reflects what
- insns are already issued in this try. MAX_POINTS is the sum of points
- of all instructions in READY. The function stops immediately,
+ insns are already issued in this try. The function stops immediately,
if it reached the such a solution, that all instruction can be issued.
INDEX will contain index of the best insn in READY. The following
function is used only for first cycle multipass scheduling.
CLOBBERs, etc must be filtered elsewhere. */
int
max_issue (struct ready_list *ready, int privileged_n, state_t state,
- int *index)
+ bool first_cycle_insn_p, int *index)
{
- int n, i, all, n_ready, best, delay, tries_num, points = -1, max_points;
+ int n, i, all, n_ready, best, delay, tries_num;
int more_issue;
struct choice_entry *top;
rtx insn;
}
/* Init max_points. */
- max_points = 0;
more_issue = issue_rate - cycle_issued_insns;
-
- /* ??? We used to assert here that we never issue more insns than issue_rate.
- However, some targets (e.g. MIPS/SB1) claim lower issue rate than can be
- achieved to get better performance. Until these targets are fixed to use
- scheduler hooks to manipulate insns priority instead, the assert should
- be disabled.
-
- gcc_assert (more_issue >= 0); */
-
- for (i = 0; i < n_ready; i++)
- if (!ready_try [i])
- {
- if (more_issue-- > 0)
- max_points += ISSUE_POINTS (ready_element (ready, i));
- else
- break;
- }
+ gcc_assert (more_issue >= 0);
/* The number of the issued insns in the best solution. */
best = 0;
memcpy (top->state, state, dfa_state_size);
top->rest = dfa_lookahead;
top->n = 0;
+ if (targetm.sched.first_cycle_multipass_begin)
+ targetm.sched.first_cycle_multipass_begin (&top->target_data,
+ ready_try, n_ready,
+ first_cycle_insn_p);
/* Count the number of the insns to search among. */
for (all = i = 0; i < n_ready; i++)
if (/* If we've reached a dead end or searched enough of what we have
been asked... */
top->rest == 0
- /* Or have nothing else to try. */
- || i >= n_ready)
+ /* or have nothing else to try... */
+ || i >= n_ready
+ /* or should not issue more. */
+ || top->n >= more_issue)
{
/* ??? (... || i == n_ready). */
gcc_assert (i <= n_ready);
+ /* We should not issue more than issue_rate instructions. */
+ gcc_assert (top->n <= more_issue);
+
if (top == choice_stack)
break;
/* This is the index of the insn issued first in this
solution. */
*index = choice_stack [1].index;
- points = top->n;
- if (top->n == max_points || best == all)
+ if (top->n == more_issue || best == all)
break;
}
}
/* Backtrack. */
ready_try [i] = 0;
+
+ if (targetm.sched.first_cycle_multipass_backtrack)
+ targetm.sched.first_cycle_multipass_backtrack (&top->target_data,
+ ready_try, n_ready);
+
top--;
memcpy (state, top->state, dfa_state_size);
}
n = top->n;
if (memcmp (top->state, state, dfa_state_size) != 0)
- n += ISSUE_POINTS (insn);
+ n++;
/* Advance to the next choice_entry. */
top++;
top->index = i;
top->n = n;
memcpy (top->state, state, dfa_state_size);
-
ready_try [i] = 1;
+
+ if (targetm.sched.first_cycle_multipass_issue)
+ targetm.sched.first_cycle_multipass_issue (&top->target_data,
+ ready_try, n_ready,
+ insn,
+ &((top - 1)
+ ->target_data));
+
i = -1;
}
}
i++;
}
+ if (targetm.sched.first_cycle_multipass_end)
+ targetm.sched.first_cycle_multipass_end (best != 0
+ ? &choice_stack[1].target_data
+ : NULL);
+
/* Restore the original state of the DFA. */
- memcpy (state, choice_stack->state, dfa_state_size);
+ memcpy (state, choice_stack->state, dfa_state_size);
return best;
}
0 if INSN_PTR is set to point to the desirable insn,
1 if choose_ready () should be restarted without advancing the cycle. */
static int
-choose_ready (struct ready_list *ready, rtx *insn_ptr)
+choose_ready (struct ready_list *ready, bool first_cycle_insn_p,
+ rtx *insn_ptr)
{
int lookahead;
if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0))
|| DEBUG_INSN_P (ready_element (ready, 0)))
{
- *insn_ptr = ready_remove_first (ready);
+ if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+ *insn_ptr = ready_remove_first_dispatch (ready);
+ else
+ *insn_ptr = ready_remove_first (ready);
+
return 0;
}
else
rtx insn;
int try_data = 1, try_control = 1;
ds_t ts;
-
+
insn = ready_element (ready, 0);
if (INSN_CODE (insn) < 0)
{
x = ready_element (ready, i);
s = TODO_SPEC (x);
-
+
if (spec_info->flags & PREFER_NON_DATA_SPEC
&& !(s & DATA_SPEC))
- {
+ {
try_data = 0;
if (!(spec_info->flags & PREFER_NON_CONTROL_SPEC)
|| !try_control)
break;
}
-
+
if (spec_info->flags & PREFER_NON_CONTROL_SPEC
&& !(s & CONTROL_SPEC))
{
{
insn = ready_element (ready, i);
-#ifdef ENABLE_CHECKING
/* If this insn is recognizable we should have already
recognized it earlier.
??? Not very clear where this is supposed to be done.
See dep_cost_1. */
- gcc_assert (INSN_CODE (insn) >= 0
- || recog_memoized (insn) < 0);
-#endif
+ gcc_checking_assert (INSN_CODE (insn) >= 0
+ || recog_memoized (insn) < 0);
ready_try [i]
= (/* INSN_CODE check can be omitted here as it is also done later
(insn)));
}
- if (max_issue (ready, 1, curr_state, &index) == 0)
+ if (max_issue (ready, 1, curr_state, first_cycle_insn_p, &index) == 0)
{
*insn_ptr = ready_remove_first (ready);
if (sched_verbose >= 4)
- fprintf (sched_dump, ";;\t\tChosen insn (but can't issue) : %s \n",
+ fprintf (sched_dump, ";;\t\tChosen insn (but can't issue) : %s \n",
(*current_sched_info->print_insn) (*insn_ptr, 0));
return 0;
}
else
{
- if (sched_verbose >= 4)
+ if (sched_verbose >= 4)
fprintf (sched_dump, ";;\t\tChosen insn : %s\n",
(*current_sched_info->print_insn)
(ready_element (ready, index), 0));
-
+
*insn_ptr = ready_remove (ready, index);
return 0;
}
void
schedule_block (basic_block *target_bb)
{
- int i, first_cycle_insn_p;
+ int i;
+ bool first_cycle_insn_p;
int can_issue_more;
state_t temp_state = NULL; /* It is used for multipass scheduling. */
int sort_p, advance, start_clock_var;
/* It is used for first cycle multipass scheduling. */
temp_state = alloca (dfa_state_size);
- if (targetm.sched.md_init)
- targetm.sched.md_init (sched_dump, sched_verbose, ready.veclen);
+ if (targetm.sched.init)
+ targetm.sched.init (sched_dump, sched_verbose, ready.veclen);
/* We start inserting insns after PREV_HEAD. */
last_scheduled_insn = prev_head;
/* Start just before the beginning of time. */
clock_var = -1;
- /* We need queue and ready lists and clock_var be initialized
+ /* We need queue and ready lists and clock_var be initialized
in try_ready () (which is called through init_ready_list ()). */
(*current_sched_info->init_ready_list) ();
else
can_issue_more = issue_rate;
- first_cycle_insn_p = 1;
+ first_cycle_insn_p = true;
cycle_issued_insns = 0;
for (;;)
{
print_curr_reg_pressure ();
}
- if (ready.n_ready == 0
- && can_issue_more
- && reload_completed)
+ if (ready.n_ready == 0
+ && can_issue_more
+ && reload_completed)
{
/* Allow scheduling insns directly from the queue in case
there's nothing better to do (ready list is empty) but
int res;
insn = NULL_RTX;
- res = choose_ready (&ready, &insn);
+ res = choose_ready (&ready, first_cycle_insn_p, &insn);
if (res < 0)
/* Finish cycle. */
to have the highest priority (so it will be returned by
the ready_remove_first call above), we invoke
ready_add (&ready, insn, true).
- But, still, there is one issue: INSN can be later
- discarded by scheduler's front end through
+ But, still, there is one issue: INSN can be later
+ discarded by scheduler's front end through
current_sched_info->can_schedule_ready_p, hence, won't
- be issued next. */
+ be issued next. */
{
ready_add (&ready, insn, true);
break;
advance = cost;
break;
}
-
+
continue;
}
continue;
}
- /* DECISION is made. */
-
+ /* DECISION is made. */
+
if (TODO_SPEC (insn) & SPECULATIVE)
generate_recovery_code (insn);
- if (control_flow_insn_p (last_scheduled_insn)
+ if (control_flow_insn_p (last_scheduled_insn)
/* This is used to switch basic blocks by request
from scheduler front-end (actually, sched-ebb.c only).
This is used to process blocks with single fallthru
{
*target_bb = current_sched_info->advance_target_bb
(*target_bb, 0);
-
+
if (sched_verbose)
{
rtx x;
last_scheduled_insn = bb_note (*target_bb);
}
-
+
/* Update counters, etc in the scheduler's front end. */
(*current_sched_info->begin_schedule_ready) (insn,
last_scheduled_insn);
-
+
move_insn (insn, last_scheduled_insn, current_sched_info->next_tail);
+
+ if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+ targetm.sched.dispatch_do (insn, ADD_TO_DISPATCH_WINDOW);
+
reemit_notes (insn);
last_scheduled_insn = insn;
-
+
if (memcmp (curr_state, temp_state, dfa_state_size) != 0)
{
cycle_issued_insns++;
if (advance != 0)
break;
- first_cycle_insn_p = 0;
+ first_cycle_insn_p = false;
/* Sort the ready list based on priority. This must be
redone here, as schedule_insn may have readied additional
/* Sanity check -- queue must be empty now. Meaningless if region has
multiple bbs. */
gcc_assert (!q_size && !ready.n_ready && !ready.n_debug);
- else
+ else
{
/* We must maintain QUEUE_INDEX between blocks in region. */
for (i = ready.n_ready - 1; i >= 0; i--)
{
rtx x;
-
+
x = ready_element (&ready, i);
QUEUE_INDEX (x) = QUEUE_NOWHERE;
TODO_SPEC (x) = (TODO_SPEC (x) & ~SPECULATIVE) | HARD_DEP;
}
- if (q_size)
+ if (q_size)
for (i = 0; i <= max_insn_queue_index; i++)
{
rtx link;
fix_inter_tick (NEXT_INSN (prev_head), last_scheduled_insn);
}
- if (targetm.sched.md_finish)
+ if (targetm.sched.finish)
{
- targetm.sched.md_finish (sched_dump, sched_verbose);
+ targetm.sched.finish (sched_dump, sched_verbose);
/* Target might have added some instructions to the scheduled block
in its md_finish () hook. These new insns don't have any data
initialized and to identify them we extend h_i_d so that they'll
{
rtx insn;
int n_insn;
- int sched_max_insns_priority =
+ int sched_max_insns_priority =
current_sched_info->sched_max_insns_priority;
rtx prev_head;
? stderr : dump_file);
}
-/* Initialize some global state for the scheduler. This function works
+/* Initialize some global state for the scheduler. This function works
with the common data shared between all the schedulers. It is called
from the scheduler specific initialization routine. */
flag_schedule_speculative_load = 0;
#endif
+ if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+ targetm.sched.dispatch_do (NULL_RTX, DISPATCH_INIT);
+
sched_pressure_p = (flag_sched_pressure && ! reload_completed
&& common_sched_info->sched_pass_id == SCHED_RGN_PASS);
+
if (sched_pressure_p)
ira_setup_eliminable_regset ();
}
df_analyze ();
-
- /* Do not run DCE after reload, as this can kill nops inserted
+
+ /* Do not run DCE after reload, as this can kill nops inserted
by bundling. */
if (reload_completed)
df_clear_flags (DF_LR_RUN_DCE);
regstat_compute_calls_crossed ();
- if (targetm.sched.md_init_global)
- targetm.sched.md_init_global (sched_dump, sched_verbose,
- get_max_uid () + 1);
+ if (targetm.sched.init_global)
+ targetm.sched.init_global (sched_dump, sched_verbose, get_max_uid () + 1);
if (sched_pressure_p)
{
saved_reg_live = BITMAP_ALLOC (NULL);
region_ref_regs = BITMAP_ALLOC (NULL);
}
-
+
curr_state = xmalloc (dfa_state_size);
}
sched_finish ();
}
-/* Free global data used during insn scheduling. This function works with
+/* Free global data used during insn scheduling. This function works with
the common data shared between the schedulers. */
void
}
free (curr_state);
- if (targetm.sched.md_finish_global)
- targetm.sched.md_finish_global (sched_dump, sched_verbose);
+ if (targetm.sched.finish_global)
+ targetm.sched.finish_global (sched_dump, sched_verbose);
end_alias_analysis ();
int next_clock = clock_var + 1;
bitmap_initialize (&processed, 0);
-
+
/* Iterates over scheduled instructions and fix their INSN_TICKs and
INSN_TICKs of dependent instructions, so that INSN_TICKs are consistent
across different blocks. */
int tick;
sd_iterator_def sd_it;
dep_t dep;
-
+
tick = INSN_TICK (head);
gcc_assert (tick >= MIN_TICK);
-
+
/* Fix INSN_TICK of instruction from just scheduled block. */
- if (!bitmap_bit_p (&processed, INSN_LUID (head)))
+ if (bitmap_set_bit (&processed, INSN_LUID (head)))
{
- bitmap_set_bit (&processed, INSN_LUID (head));
tick -= next_clock;
-
+
if (tick < MIN_TICK)
tick = MIN_TICK;
-
- INSN_TICK (head) = tick;
+
+ INSN_TICK (head) = tick;
}
-
+
FOR_EACH_DEP (head, SD_LIST_RES_FORW, sd_it, dep)
{
rtx next;
-
+
next = DEP_CON (dep);
tick = INSN_TICK (next);
/* If NEXT has its INSN_TICK calculated, fix it.
If not - it will be properly calculated from
scratch later in fix_tick_ready. */
- && !bitmap_bit_p (&processed, INSN_LUID (next)))
+ && bitmap_set_bit (&processed, INSN_LUID (next)))
{
- bitmap_set_bit (&processed, INSN_LUID (next));
tick -= next_clock;
-
+
if (tick < MIN_TICK)
tick = MIN_TICK;
-
+
if (tick > INTER_TICK (next))
INTER_TICK (next) = tick;
else
}
static int haifa_speculate_insn (rtx, ds_t, rtx *);
-
+
/* Check if NEXT is ready to be added to the ready or queue list.
If "yes", add it to the proper list.
Returns:
0 < N - queued for N cycles. */
int
try_ready (rtx next)
-{
+{
ds_t old_ts, *ts;
ts = &TODO_SPEC (next);
gcc_assert (!(old_ts & ~(SPECULATIVE | HARD_DEP))
&& ((old_ts & HARD_DEP)
|| (old_ts & SPECULATIVE)));
-
+
if (sd_lists_empty_p (next, SD_LIST_BACK))
/* NEXT has all its dependencies resolved. */
{
{
ds_t ds = DEP_STATUS (dep) & SPECULATIVE;
+ if (DEBUG_INSN_P (DEP_PRO (dep))
+ && !DEBUG_INSN_P (next))
+ continue;
+
if (first_p)
{
first_p = false;
{
int res;
rtx new_pat;
-
+
gcc_assert ((*ts & SPECULATIVE) && !(*ts & ~SPECULATIVE));
-
+
res = haifa_speculate_insn (next, *ts, &new_pat);
-
+
switch (res)
{
case -1:
so we won't reanalyze anything. */
*ts = (*ts & ~SPECULATIVE) | HARD_DEP;
break;
-
+
case 0:
/* We follow the rule, that every speculative insn
has non-null ORIG_PAT. */
if (!ORIG_PAT (next))
ORIG_PAT (next) = PATTERN (next);
break;
-
- case 1:
+
+ case 1:
if (!ORIG_PAT (next))
/* If we gonna to overwrite the original pattern of insn,
save it. */
ORIG_PAT (next) = PATTERN (next);
-
+
haifa_change_pattern (next, new_pat);
break;
-
+
default:
gcc_unreachable ();
}
}
-
+
/* We need to restore pattern only if (*ts == 0), because otherwise it is
either correct (*ts & SPECULATIVE),
or we simply don't care (*ts & HARD_DEP). */
-
+
gcc_assert (!ORIG_PAT (next)
|| !IS_SPECULATION_BRANCHY_CHECK_P (next));
-
+
if (*ts & HARD_DEP)
{
/* We can't assert (QUEUE_INDEX (next) == QUEUE_NOWHERE) here because
control-speculative NEXT could have been discarded by sched-rgn.c
(the same case as when discarded by can_schedule_ready_p ()). */
/*gcc_assert (QUEUE_INDEX (next) == QUEUE_NOWHERE);*/
-
+
change_queue_index (next, QUEUE_NOWHERE);
return -1;
}
else if (!(*ts & BEGIN_SPEC) && ORIG_PAT (next) && !IS_SPECULATION_CHECK_P (next))
- /* We should change pattern of every previously speculative
+ /* We should change pattern of every previously speculative
instruction - and we determine if NEXT was speculative by using
ORIG_PAT field. Except one case - speculation checks have ORIG_PAT
pat too, so skip them. */
}
if (sched_verbose >= 2)
- {
+ {
int s = TODO_SPEC (next);
-
+
fprintf (sched_dump, ";;\t\tdependencies resolved: insn %s",
(*current_sched_info->print_insn) (next, 0));
-
+
if (spec_info && spec_info->dump)
{
if (s & BEGIN_DATA)
}
fprintf (sched_dump, "\n");
- }
-
+ }
+
adjust_priority (next);
-
+
return fix_tick_ready (next);
}
full_p = (tick == INVALID_TICK);
FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep)
- {
+ {
rtx pro = DEP_PRO (dep);
int tick1;
-
+
gcc_assert (INSN_TICK (pro) >= MIN_TICK);
tick1 = INSN_TICK (pro) + dep_cost (dep);
{
int i = QUEUE_INDEX (next);
- gcc_assert (QUEUE_NOWHERE <= delay && delay <= max_insn_queue_index
+ gcc_assert (QUEUE_NOWHERE <= delay && delay <= max_insn_queue_index
&& delay != 0);
gcc_assert (i != QUEUE_SCHEDULED);
-
+
if ((delay > 0 && NEXT_Q_AFTER (q_ptr, delay) == i)
|| (delay < 0 && delay == i))
/* We have nothing to do. */
ready_remove_insn (next);
else if (i >= 0)
queue_remove (next);
-
+
/* Add it to the proper place. */
if (delay == QUEUE_READY)
ready_add (readyp, next, false);
else if (delay >= 1)
queue_insn (next, delay);
-
+
if (sched_verbose >= 2)
- {
+ {
fprintf (sched_dump, ";;\t\ttick updated: insn %s",
(*current_sched_info->print_insn) (next, 0));
-
+
if (delay == QUEUE_READY)
fprintf (sched_dump, " into ready\n");
else if (delay >= 1)
new_sched_ready_n_insns + 1);
for (; i <= new_sched_ready_n_insns; i++)
- choice_stack[i].state = xmalloc (dfa_state_size);
+ {
+ choice_stack[i].state = xmalloc (dfa_state_size);
+
+ if (targetm.sched.first_cycle_multipass_init)
+ targetm.sched.first_cycle_multipass_init (&(choice_stack[i]
+ .target_data));
+ }
sched_ready_n_insns = new_sched_ready_n_insns;
}
ready_try = NULL;
for (i = 0; i <= sched_ready_n_insns; i++)
- free (choice_stack [i].state);
+ {
+ if (targetm.sched.first_cycle_multipass_fini)
+ targetm.sched.first_cycle_multipass_fini (&(choice_stack[i]
+ .target_data));
+
+ free (choice_stack [i].state);
+ }
free (choice_stack);
choice_stack = NULL;
{
if (TODO_SPEC (insn) & BEGIN_SPEC)
begin_speculative_block (insn);
-
+
/* Here we have insn with no dependencies to
instructions other then CHECK_SPEC ones. */
-
+
if (TODO_SPEC (insn) & BE_IN_SPEC)
add_to_speculative_block (insn);
}
ds_t new_ds;
new_ds = (ds & ~BEGIN_SPEC) | fs;
-
+
if (/* consumer can 'be in speculative'. */
sched_insn_is_legitimate_for_speculation_p (consumer,
new_ds))
begin_speculative_block (rtx insn)
{
if (TODO_SPEC (insn) & BEGIN_DATA)
- nr_begin_data++;
+ nr_begin_data++;
if (TODO_SPEC (insn) & BEGIN_CONTROL)
nr_begin_control++;
TODO_SPEC (insn) &= ~BE_IN_SPEC;
gcc_assert (!TODO_SPEC (insn));
-
+
DONE_SPEC (insn) |= ts;
/* First we convert all simple checks to branchy. */
twin = XEXP (twins, 1);
free_INSN_LIST_node (twins);
- twins = twin;
+ twins = twin;
}
calc_priorities (priorities_roots);
/* Helper function.
Find fallthru edge from PRED. */
edge
-find_fallthru_edge (basic_block pred)
+find_fallthru_edge_from (basic_block pred)
{
edge e;
- edge_iterator ei;
basic_block succ;
succ = pred->next_bb;
if (EDGE_COUNT (pred->succs) <= EDGE_COUNT (succ->preds))
{
- FOR_EACH_EDGE (e, ei, pred->succs)
- if (e->flags & EDGE_FALLTHRU)
- {
- gcc_assert (e->dest == succ);
- return e;
- }
+ e = find_fallthru_edge (pred->succs);
+
+ if (e)
+ {
+ gcc_assert (e->dest == succ);
+ return e;
+ }
}
else
{
- FOR_EACH_EDGE (e, ei, succ->preds)
- if (e->flags & EDGE_FALLTHRU)
- {
- gcc_assert (e->src == pred);
- return e;
- }
+ e = find_fallthru_edge (succ->preds);
+
+ if (e)
+ {
+ gcc_assert (e->src == pred);
+ return e;
+ }
}
return NULL;
edge e;
last = EXIT_BLOCK_PTR->prev_bb;
- e = find_fallthru_edge (last);
+ e = find_fallthru_edge_from (last);
if (e)
{
- /* We create two basic blocks:
+ /* We create two basic blocks:
1. Single instruction block is inserted right after E->SRC
- and has jump to
+ and has jump to
2. Empty block right before EXIT_BLOCK.
Between these two blocks recovery blocks will be emitted. */
basic_block single, empty;
rtx x, label;
- /* If the fallthrough edge to exit we've found is from the block we've
+ /* If the fallthrough edge to exit we've found is from the block we've
created before, don't do anything more. */
if (last == after_recovery)
return;
JUMP_LABEL (x) = label;
LABEL_NUSES (label)++;
haifa_init_insn (x);
-
+
emit_barrier_after (x);
sched_init_only_bb (empty, NULL);
if (sched_verbose >= 2 && spec_info->dump)
fprintf (spec_info->dump,
- ";;\t\tFixed fallthru to EXIT : %d->>%d->%d->>EXIT\n",
- last->index, single->index, empty->index);
+ ";;\t\tFixed fallthru to EXIT : %d->>%d->%d->>EXIT\n",
+ last->index, single->index, empty->index);
}
else
before_recovery = last;
rtx label;
rtx barrier;
basic_block rec;
-
+
haifa_recovery_bb_recently_added_p = true;
haifa_recovery_bb_ever_added_p = true;
if (BB_PARTITION (before_recovery) != BB_UNPARTITIONED)
BB_SET_PARTITION (rec, BB_COLD_PARTITION);
-
- if (sched_verbose && spec_info->dump)
+
+ if (sched_verbose && spec_info->dump)
fprintf (spec_info->dump, ";;\t\tGenerated recovery block rec%d\n",
rec->index);
{
rtx label;
rtx jump;
- edge e;
int edge_flags;
/* This is fixing of incoming edge. */
- /* ??? Which other flags should be specified? */
+ /* ??? Which other flags should be specified? */
if (BB_PARTITION (first_bb) != BB_PARTITION (rec))
/* Partition type is the same, if it is "unpartitioned". */
edge_flags = EDGE_CROSSING;
else
edge_flags = 0;
-
- e = make_edge (first_bb, rec, edge_flags);
+
+ make_edge (first_bb, rec, edge_flags);
label = block_label (second_bb);
jump = emit_jump_insn_after (gen_jump (label), BB_END (rec));
JUMP_LABEL (jump) = label;
edge_flags = EDGE_CROSSING;
}
else
- edge_flags = 0;
+ edge_flags = 0;
- make_single_succ_edge (rec, second_bb, edge_flags);
+ make_single_succ_edge (rec, second_bb, edge_flags);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, rec, first_bb);
}
/* This function creates recovery code for INSN. If MUTATE_P is nonzero,
if (rec != EXIT_BLOCK_PTR)
{
/* To have mem_reg alive at the beginning of second_bb,
- we emit check BEFORE insn, so insn after splitting
+ we emit check BEFORE insn, so insn after splitting
insn will be at the beginning of second_bb, which will
provide us with the correct life information. */
check = emit_jump_insn_before (check, insn);
sched_create_recovery_edges (first_bb, rec, second_bb);
- sched_init_only_bb (second_bb, first_bb);
+ sched_init_only_bb (second_bb, first_bb);
sched_init_only_bb (rec, EXIT_BLOCK_PTR);
jump = BB_END (rec);
haifa_init_insn (jump);
}
- /* Move backward dependences from INSN to CHECK and
+ /* Move backward dependences from INSN to CHECK and
move forward dependences from INSN to TWIN. */
/* First, create dependencies between INSN's producers and CHECK & TWIN. */
check --TRUE--> producer ??? or ANTI ???
twin --TRUE--> producer
twin --ANTI--> check
-
+
If BEGIN_CONTROL: [insn ~~ANTI~~> producer]:
check --ANTI--> producer
twin --ANTI--> producer
If BE_IN_SPEC: [insn ~~TRUE~~> producer]:
check ~~TRUE~~> producer
twin ~~TRUE~~> producer
- twin --ANTI--> check */
+ twin --ANTI--> check */
ds = DEP_STATUS (dep);
{
DEP_CON (new_dep) = twin;
sd_add_dep (new_dep, false);
- }
+ }
}
/* Second, remove backward dependencies of INSN. */
/* Fields (DONE_SPEC (x) & BEGIN_SPEC) and CHECK_SPEC (x) are set only
here. */
-
+
gcc_assert (!DONE_SPEC (insn));
-
+
if (!mutate_p)
- {
+ {
ds_t ts = TODO_SPEC (insn);
DONE_SPEC (insn) = ts & BEGIN_SPEC;
}
else
{
- if (spec_info->dump)
+ if (spec_info->dump)
fprintf (spec_info->dump, ";;\t\tRemoved simple check : %s\n",
(*current_sched_info->print_insn) (insn, 0));
rtx link;
bitmap_initialize (&in_ready, 0);
-
+
/* NOTE - a basic block note. */
note = NEXT_INSN (BB_HEAD (rec));
gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
{
sd_delete_dep (sd_it);
- if (!bitmap_bit_p (&in_ready, INSN_LUID (consumer)))
- {
- ready_list = alloc_INSN_LIST (consumer, ready_list);
- bitmap_set_bit (&in_ready, INSN_LUID (consumer));
- }
+ if (bitmap_set_bit (&in_ready, INSN_LUID (consumer)))
+ ready_list = alloc_INSN_LIST (consumer, ready_list);
}
else
{
sd_iterator_next (&sd_it);
}
}
-
+
insn = PREV_INSN (insn);
}
while (insn != note);
/* Fixing jump's dependences. */
insn = BB_HEAD (rec);
jump = BB_END (rec);
-
+
gcc_assert (LABEL_P (insn));
insn = NEXT_INSN (insn);
-
+
gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn));
add_jump_dependencies (insn, jump);
}
if (LABEL_P (label))
note = NEXT_INSN (label);
else
- note = label;
+ note = label;
gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
prev = PREV_INSN (label);
if (last == first)
break;
-
+
last = last->prev_bb;
}
while (1);
return;
/* We DON'T unlink basic block notes of the first block in the ebb. */
- first = first->next_bb;
+ first = first->next_bb;
/* Remember: FIRST is actually a second basic block in the ebb. */
while (first != EXIT_BLOCK_PTR
&& bb_header[first->index])
{
rtx prev, label, note, next;
-
+
label = bb_header[first->index];
prev = PREV_INSN (label);
next = NEXT_INSN (prev);
if (LABEL_P (label))
note = NEXT_INSN (label);
else
- note = label;
+ note = label;
gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
bb_header[first->index] = 0;
NEXT_INSN (prev) = label;
NEXT_INSN (note) = next;
PREV_INSN (next) = note;
-
+
first = first->next_bb;
}
gcc_assert (common_sched_info->sched_pass_id == SCHED_EBB_PASS
|| IS_SPECULATION_BRANCHY_CHECK_P (jump));
-
+
if (!NOTE_INSN_BASIC_BLOCK_P (BB_END (jump_bb_next)))
/* if jump_bb_next is not empty. */
BB_END (jump_bb) = BB_END (jump_bb_next);
bb = BLOCK_FOR_INSN (PREV_INSN (jump));
jump_bb = BLOCK_FOR_INSN (jump);
jump_bb_next = jump_bb->next_bb;
-
+
update_bb_for_insn (jump_bb);
-
+
gcc_assert (IS_SPECULATION_CHECK_P (jump)
|| IS_SPECULATION_CHECK_P (BB_END (jump_bb_next)));
move_succs (&t, jump_bb_next);
df_mark_solutions_dirty ();
-
+
common_sched_info->fix_recovery_cfg
(bb->index, jump_bb->index, jump_bb_next->index);
}
int i;
rtx insn;
- for (i = 0; VEC_iterate (rtx, roots, i, insn); i++)
+ FOR_EACH_VEC_ELT (rtx, roots, i, insn)
priority (insn);
}
insn = NEXT_INSN (insn);
if (insn == jump)
break;
-
+
if (dep_list_size (insn) == 0)
{
dep_def _new_dep, *new_dep = &_new_dep;
next_tail = NEXT_INSN (tail);
do
- {
- not_last = head != tail;
+ {
+ not_last = head != tail;
if (not_first)
gcc_assert (NEXT_INSN (PREV_INSN (head)) == head);
if (not_last)
gcc_assert (PREV_INSN (NEXT_INSN (head)) == head);
- if (LABEL_P (head)
+ if (LABEL_P (head)
|| (NOTE_INSN_BASIC_BLOCK_P (head)
&& (!not_first
|| (not_first && !LABEL_P (PREV_INSN (head))))))
{
- gcc_assert (bb == 0);
+ gcc_assert (bb == 0);
bb = BLOCK_FOR_INSN (head);
if (bb != 0)
- gcc_assert (BB_HEAD (bb) == head);
+ gcc_assert (BB_HEAD (bb) == head);
else
/* This is the case of jump table. See inside_basic_block_p (). */
gcc_assert (LABEL_P (head) && !inside_basic_block_p (head));
gcc_assert (inside_basic_block_p (head)
|| NOTE_P (head));
gcc_assert (BLOCK_FOR_INSN (head) == bb);
-
+
if (LABEL_P (head))
{
head = NEXT_INSN (head);
unsigned i;
basic_block x;
- for (i = 0; VEC_iterate (basic_block, bbs, i, x); i++)
+ FOR_EACH_VEC_ELT (basic_block, bbs, i, x)
init_bb (x);
}
extend_insn ();
if (bbs != NULL)
- {
+ {
unsigned i;
basic_block x;
- for (i = 0; VEC_iterate (basic_block, bbs, i, x); i++)
+ FOR_EACH_VEC_ELT (basic_block, bbs, i, x)
init_insns_in_bb (x);
}
unsigned i;
rtx x;
- for (i = 0; VEC_iterate (rtx, insns, i, x); i++)
+ FOR_EACH_VEC_ELT (rtx, insns, i, x)
init_insn (x);
}
static void
extend_h_i_d (void)
{
- int reserve = (get_max_uid () + 1
+ int reserve = (get_max_uid () + 1
- VEC_length (haifa_insn_data_def, h_i_d));
- if (reserve > 0
+ if (reserve > 0
&& ! VEC_space (haifa_insn_data_def, h_i_d, reserve))
{
- VEC_safe_grow_cleared (haifa_insn_data_def, heap, h_i_d,
+ VEC_safe_grow_cleared (haifa_insn_data_def, heap, h_i_d,
3 * get_max_uid () / 2);
sched_extend_target ();
}
haifa_insn_data_t data;
struct reg_use_data *use, *next;
- for (i = 0; VEC_iterate (haifa_insn_data_def, h_i_d, i, data); i++)
+ FOR_EACH_VEC_ELT (haifa_insn_data_def, h_i_d, i, data)
{
if (data->reg_pressure != NULL)
free (data->reg_pressure);
e = split_block (first_bb, after);
gcc_assert (e->src == first_bb);
- /* sched_split_block emits note if *check == BB_END. Probably it
+ /* sched_split_block emits note if *check == BB_END. Probably it
is better to rip that note off. */
return e->dest;
return insn;
}
+/* This function returns a candidate satisfying dispatch constraints from
+ the ready list. */
+
+static rtx
+ready_remove_first_dispatch (struct ready_list *ready)
+{
+ int i;
+ rtx insn = ready_element (ready, 0);
+
+ if (ready->n_ready == 1
+ || INSN_CODE (insn) < 0
+ || !INSN_P (insn)
+ || !active_insn_p (insn)
+ || targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+ return ready_remove_first (ready);
+
+ for (i = 1; i < ready->n_ready; i++)
+ {
+ insn = ready_element (ready, i);
+
+ if (INSN_CODE (insn) < 0
+ || !INSN_P (insn)
+ || !active_insn_p (insn))
+ continue;
+
+ if (targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+ {
+ /* Return ith element of ready. */
+ insn = ready_remove (ready, i);
+ return insn;
+ }
+ }
+
+ if (targetm.sched.dispatch (NULL_RTX, DISPATCH_VIOLATION))
+ return ready_remove_first (ready);
+
+ for (i = 1; i < ready->n_ready; i++)
+ {
+ insn = ready_element (ready, i);
+
+ if (INSN_CODE (insn) < 0
+ || !INSN_P (insn)
+ || !active_insn_p (insn))
+ continue;
+
+ /* Return i-th element of ready. */
+ if (targetm.sched.dispatch (insn, IS_CMP))
+ return ready_remove (ready, i);
+ }
+
+ return ready_remove_first (ready);
+}
+
+/* Get number of ready insn in the ready list. */
+
+int
+number_in_ready (void)
+{
+ return ready.n_ready;
+}
+
+/* Get number of ready's in the ready list. */
+
+rtx
+get_ready_element (int i)
+{
+ return ready_element (&ready, i);
+}
+
#endif /* INSN_SCHEDULING */