/* 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
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;
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
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;
}
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;
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);
}
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. */
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)
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);
-
- while (insn != tail && NOTE_NOT_BB_P (insn))
- {
- rtx next = NEXT_INSN (insn);
- basic_block bb = BLOCK_FOR_INSN (insn);
+ rtx next_tail, insn, next;
- /* 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;
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)
{
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, 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;
- 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);
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
{
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)
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;
else
can_issue_more = issue_rate;
- first_cycle_insn_p = 1;
+ first_cycle_insn_p = true;
cycle_issued_insns = 0;
for (;;)
{
int res;
insn = NULL_RTX;
- res = choose_ready (&ready, &insn);
+ res = choose_ready (&ready, first_cycle_insn_p, &insn);
if (res < 0)
/* Finish cycle. */
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 (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
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
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 ();
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)
{
}
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 ();
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)
/* 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)
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;
/* 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)
{
edge_flags = 0;
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,
{
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
{
int i;
rtx insn;
- for (i = 0; VEC_iterate (rtx, roots, i, insn); i++)
+ FOR_EACH_VEC_ELT (rtx, roots, i, insn)
priority (insn);
}
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);
}
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);
}
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);
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 */