haifa-sched.c: Include "hashtab.h"

* haifa-sched.c: Include "hashtab.h"
	(sched_no_dce): New global variable.
	(INSN_EXACT_TICK, INSN_TICK_ESTIMATE, FEEDS_BACKTRACK_INSN,
	SHADOW_P): New macros.
	(last_clock_var, cycle_issued_insns): Move declarations.
	(must_backtrack): New static variable.
	(struct delay_pair): New structure.
	(delay_htab, delay_htab_i2): New static variables.
	(delay_hash_i1, delay_hash_i2, delay_i1_eq, delay_i2_eq,
	record_delay_slot_pair, pair_delay, add_delay_dependencies): New
	functions.
	(dep_cost_1): If delay pairs exist, try to look up the insns and
	use the correct pair delay if we find them.
	(rank-for_schedule): Tweak priority for insns that must be scheduled
	soon to avoid backtracking.
	(queue_insn): Detect conditions which force backtracking.
	(ready_add): Likewise.
	(struct sched_block_state): Add member shadows_only_p.
	(struct haifa_save_data): New structure.
	(backtrack_queue): New static variable.
	(mark_backtrack_feeds, copy_insn_list, save_backtrack_point,
	unschedule_insns_until, restore_last_backtrack_point,
	free_topmost_backtrack_point, free_backtrack_queue,
	estimate_insn_tick, estimate_shadow_tick): New functions.
	(prune_ready_list): New arg shadows_only_p.  All callers changed.
	If true, remove everything that isn't SHADOW_P.  Look up delay
	pairs and estimate ticks to avoid scheduling the first insn too
	early.
	(verify_shadows): New function.
	(schedule_block): Add machinery to enable backtracking.
	(sched_init): Take sched_no_dce into account when setting
	DF_LR_RUN_DCE.
	(free_delay_pairs): New function.
	(init_h_i_d): Initialize INSN_EXACT_TICK.
	* Makefile.in (haifa-sched.o): Add $(HASHTAB_H).
	* sched-deps.c (sd_unresolve_dep): New function.
	* sched-int.h (struct haifa_sched_info): New fields save_state
	and restore_state.
	(struct _haifa_insn_data): New fields exact_tick, tick_estimate,
	feeds_backtrack_insn and shadow_p.
	(DO_BACKTRACKING): New value in enum SCHED_FLAGS.
	(sched_no_dce): Declare variable.
	(record_delay_slot_pair, free_delay_pairs, add_delay_dependencies,
	sd_unresolve_dep): Declare functions.
	* modulo-sched.c (sms_sched_info): Clear the two new fields.
	* sched-rgn.c (rgn_const_sched_info): Likewise.
	* sel-sched-ir.c (sched_sel_haifa_sched_info): Likewise.
	* sched-ebb.c (save_ebb_state, restore_ebb_state): New functions.
	(ebb_sched_info): Add them for the two new fields.
	(add_deps_for_risky_insns): Call add_delay_dependencies.

From-SVN: r176255
This commit is contained in:
Bernd Schmidt 2011-07-13 23:10:52 +00:00 committed by Bernd Schmidt
parent 13b7a7b9d8
commit 26965010b9
9 changed files with 975 additions and 80 deletions

View File

@ -1,3 +1,56 @@
2011-07-14 Bernd Schmidt <bernds@codesourcery.com>
* haifa-sched.c: Include "hashtab.h"
(sched_no_dce): New global variable.
(INSN_EXACT_TICK, INSN_TICK_ESTIMATE, FEEDS_BACKTRACK_INSN,
SHADOW_P): New macros.
(last_clock_var, cycle_issued_insns): Move declarations.
(must_backtrack): New static variable.
(struct delay_pair): New structure.
(delay_htab, delay_htab_i2): New static variables.
(delay_hash_i1, delay_hash_i2, delay_i1_eq, delay_i2_eq,
record_delay_slot_pair, pair_delay, add_delay_dependencies): New
functions.
(dep_cost_1): If delay pairs exist, try to look up the insns and
use the correct pair delay if we find them.
(rank-for_schedule): Tweak priority for insns that must be scheduled
soon to avoid backtracking.
(queue_insn): Detect conditions which force backtracking.
(ready_add): Likewise.
(struct sched_block_state): Add member shadows_only_p.
(struct haifa_save_data): New structure.
(backtrack_queue): New static variable.
(mark_backtrack_feeds, copy_insn_list, save_backtrack_point,
unschedule_insns_until, restore_last_backtrack_point,
free_topmost_backtrack_point, free_backtrack_queue,
estimate_insn_tick, estimate_shadow_tick): New functions.
(prune_ready_list): New arg shadows_only_p. All callers changed.
If true, remove everything that isn't SHADOW_P. Look up delay
pairs and estimate ticks to avoid scheduling the first insn too
early.
(verify_shadows): New function.
(schedule_block): Add machinery to enable backtracking.
(sched_init): Take sched_no_dce into account when setting
DF_LR_RUN_DCE.
(free_delay_pairs): New function.
(init_h_i_d): Initialize INSN_EXACT_TICK.
* Makefile.in (haifa-sched.o): Add $(HASHTAB_H).
* sched-deps.c (sd_unresolve_dep): New function.
* sched-int. (struct haifa_sched_info): New fields save_state
and restore_state.
(struct _haifa_insn_data): New fields exact_tick, tick_estimate,
feeds_backtrack_insn and shadow_p.
(DO_BACKTRACKING): New value in enum SCHED_FLAGS.
(sched_no_dce): Declare variable.
(record_delay_slot_pair, free_delay_pairs, add_delay_dependencies,
sd_unresolve_dep): Declare functions.
* modulo-sched.c (sms_sched_info): Clear the two new fields.
* sched-rgn.c (rgn_const_sched_info): Likewise.
* sel-sched-ir.c (sched_sel_haifa_sched_info): Likewise.
* sched-ebb.c (save_ebb_state, restore_ebb_state): New functions.
(ebb_sched_info): Add them for the two new fields.
(add_deps_for_risky_insns): Call add_delay_dependencies.
2011-07-13 Michael Meissner <meissner@linux.vnet.ibm.com>
* config/rs6000/rs6000.opt (-mpointers-to-nested-functions):

View File

@ -3397,7 +3397,8 @@ modulo-sched.o : modulo-sched.c $(DDG_H) $(CONFIG_H) $(CONFIG_H) $(SYSTEM_H) \
haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h $(FUNCTION_H) \
$(INSN_ATTR_H) $(DIAGNOSTIC_CORE_H) $(RECOG_H) $(EXCEPT_H) $(TM_P_H) $(TARGET_H) output.h \
$(PARAMS_H) $(DBGCNT_H) $(CFGLOOP_H) ira.h $(EMIT_RTL_H) $(COMMON_TARGET_H)
$(PARAMS_H) $(DBGCNT_H) $(CFGLOOP_H) ira.h $(EMIT_RTL_H) $(COMMON_TARGET_H) \
$(HASHTAB_H)
sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
$(FUNCTION_H) $(INSN_ATTR_H) $(DIAGNOSTIC_CORE_H) $(RECOG_H) $(EXCEPT_H) cselib.h \

View File

@ -149,6 +149,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "ira.h"
#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
#include "hashtab.h"
#ifdef INSN_SCHEDULING
@ -158,6 +159,10 @@ along with GCC; see the file COPYING3. If not see
int issue_rate;
/* This can be set to true by a backend if the scheduler should not
enable a DCE pass. */
bool sched_no_dce;
/* sched-verbose controls the amount of debugging output the
scheduler prints. It is controlled by -fsched-verbose=N:
N>0 and no -DSR : the output is directed to stderr.
@ -178,7 +183,11 @@ FILE *sched_dump = 0;
struct common_sched_info_def *common_sched_info;
#define INSN_TICK(INSN) (HID (INSN)->tick)
#define INSN_EXACT_TICK(INSN) (HID (INSN)->exact_tick)
#define INSN_TICK_ESTIMATE(INSN) (HID (INSN)->tick_estimate)
#define INTER_TICK(INSN) (HID (INSN)->inter_tick)
#define FEEDS_BACKTRACK_INSN(INSN) (HID (INSN)->feeds_backtrack_insn)
#define SHADOW_P(INSN) (HID (INSN)->shadow_p)
/* If INSN_TICK of an instruction is equal to INVALID_TICK,
then it should be recalculated from scratch. */
@ -303,6 +312,18 @@ static struct ready_list *readyp = &ready;
/* Scheduling clock. */
static int clock_var;
/* Clock at which the previous instruction was issued. */
static int last_clock_var;
/* Set to true if, when queuing a shadow insn, we discover that it would be
scheduled too late. */
static bool must_backtrack;
/* The following variable value is number of essential insns issued on
the current cycle. An insn is essential one if it changes the
processors state. */
int cycle_issued_insns;
/* This records the actual schedule. It is built up during the main phase
of schedule_block, and afterwards used to reorder the insns in the RTL. */
static VEC(rtx, heap) *scheduled_insns;
@ -487,6 +508,147 @@ haifa_classify_insn (const_rtx insn)
return haifa_classify_rtx (PATTERN (insn));
}
/* A structure to record a pair of insns where the first one is a real
insn that has delay slots, and the second is its delayed shadow.
I1 is scheduled normally and will emit an assembly instruction,
while I2 describes the side effect that takes place at the
transition between cycles CYCLES and (CYCLES + 1) after I1. */
struct delay_pair
{
struct delay_pair *next_same_i1;
rtx i1, i2;
int cycles;
};
/* Two hash tables to record delay_pairs, one indexed by I1 and the other
indexed by I2. */
static htab_t delay_htab;
static htab_t delay_htab_i2;
/* Returns a hash value for X (which really is a delay_pair), based on
hashing just I1. */
static hashval_t
delay_hash_i1 (const void *x)
{
return htab_hash_pointer (((const struct delay_pair *) x)->i1);
}
/* Returns a hash value for X (which really is a delay_pair), based on
hashing just I2. */
static hashval_t
delay_hash_i2 (const void *x)
{
return htab_hash_pointer (((const struct delay_pair *) x)->i2);
}
/* Return nonzero if I1 of pair X is the same as that of pair Y. */
static int
delay_i1_eq (const void *x, const void *y)
{
return ((const struct delay_pair *) x)->i1 == y;
}
/* Return nonzero if I2 of pair X is the same as that of pair Y. */
static int
delay_i2_eq (const void *x, const void *y)
{
return ((const struct delay_pair *) x)->i2 == y;
}
/* This function can be called by a port just before it starts the
final scheduling pass. It records the fact that an instruction
with delay slots has been split into two insns, I1 and I2. The
first one will be scheduled normally and initiates the operation.
The second one is a shadow which must follow a specific number of
CYCLES after I1; its only purpose is to show the side effect that
occurs at that cycle in the RTL. If a JUMP_INSN or a CALL_INSN has
been split, I1 should be a normal INSN, while I2 retains the
original insn type. */
void
record_delay_slot_pair (rtx i1, rtx i2, int cycles)
{
struct delay_pair *p = XNEW (struct delay_pair);
struct delay_pair **slot;
p->i1 = i1;
p->i2 = i2;
p->cycles = cycles;
if (!delay_htab)
{
delay_htab = htab_create (10, delay_hash_i1, delay_i1_eq, NULL);
delay_htab_i2 = htab_create (10, delay_hash_i2, delay_i2_eq, free);
}
slot = ((struct delay_pair **)
htab_find_slot_with_hash (delay_htab, i1, htab_hash_pointer (i1),
INSERT));
p->next_same_i1 = *slot;
*slot = p;
slot = ((struct delay_pair **)
htab_find_slot_with_hash (delay_htab_i2, i2, htab_hash_pointer (i2),
INSERT));
*slot = p;
}
/* For a pair P of insns, return the fixed distance in cycles from the first
insn after which the second must be scheduled. */
static int
pair_delay (struct delay_pair *p)
{
return p->cycles;
}
/* Given an insn INSN, add a dependence on its delayed shadow if it
has one. Also try to find situations where shadows depend on each other
and add dependencies to the real insns to limit the amount of backtracking
needed. */
void
add_delay_dependencies (rtx insn)
{
struct delay_pair *pair;
sd_iterator_def sd_it;
dep_t dep;
if (!delay_htab)
return;
pair
= (struct delay_pair *)htab_find_with_hash (delay_htab_i2, insn,
htab_hash_pointer (insn));
if (!pair)
return;
add_dependence (insn, pair->i1, REG_DEP_ANTI);
FOR_EACH_DEP (pair->i2, SD_LIST_BACK, sd_it, dep)
{
rtx pro = DEP_PRO (dep);
struct delay_pair *other_pair
= (struct delay_pair *)htab_find_with_hash (delay_htab_i2, pro,
htab_hash_pointer (pro));
if (!other_pair)
continue;
if (pair_delay (other_pair) >= pair_delay (pair))
{
if (sched_verbose >= 4)
{
fprintf (sched_dump, ";;\tadding dependence %d <- %d\n",
INSN_UID (other_pair->i1),
INSN_UID (pair->i1));
fprintf (sched_dump, ";;\tpair1 %d <- %d, cost %d\n",
INSN_UID (pair->i1),
INSN_UID (pair->i2),
pair_delay (pair));
fprintf (sched_dump, ";;\tpair2 %d <- %d, cost %d\n",
INSN_UID (other_pair->i1),
INSN_UID (other_pair->i2),
pair_delay (other_pair));
}
add_dependence (pair->i1, other_pair->i1, REG_DEP_ANTI);
}
}
}
/* Forward declarations. */
static int priority (rtx);
@ -857,6 +1019,22 @@ dep_cost_1 (dep_t link, dw_t dw)
if (DEP_COST (link) != UNKNOWN_DEP_COST)
return DEP_COST (link);
if (delay_htab)
{
struct delay_pair *delay_entry;
delay_entry
= (struct delay_pair *)htab_find_with_hash (delay_htab_i2, used,
htab_hash_pointer (used));
if (delay_entry)
{
if (delay_entry->i1 == insn)
{
DEP_COST (link) = pair_delay (delay_entry);
return DEP_COST (link);
}
}
}
/* A USE insn should never require the value used to be computed.
This allows the computation of a function's result and parameter
values to overlap the return and call. We don't care about the
@ -1213,6 +1391,17 @@ rank_for_schedule (const void *x, const void *y)
else
return INSN_TICK (tmp) - INSN_TICK (tmp2);
}
/* If we are doing backtracking in this schedule, prefer insns that
have forward dependencies with negative cost against an insn that
was already scheduled. */
if (current_sched_info->flags & DO_BACKTRACKING)
{
priority_val = FEEDS_BACKTRACK_INSN (tmp2) - FEEDS_BACKTRACK_INSN (tmp);
if (priority_val)
return priority_val;
}
/* Prefer insn with higher priority. */
priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
@ -1325,6 +1514,7 @@ queue_insn (rtx insn, int n_cycles, const char *reason)
{
int next_q = NEXT_Q_AFTER (q_ptr, n_cycles);
rtx link = alloc_INSN_LIST (insn, insn_queue[next_q]);
int new_tick;
gcc_assert (n_cycles <= max_insn_queue_index);
gcc_assert (!DEBUG_INSN_P (insn));
@ -1341,6 +1531,21 @@ queue_insn (rtx insn, int n_cycles, const char *reason)
}
QUEUE_INDEX (insn) = next_q;
if (current_sched_info->flags & DO_BACKTRACKING)
{
new_tick = clock_var + n_cycles;
if (INSN_TICK (insn) == INVALID_TICK || INSN_TICK (insn) < new_tick)
INSN_TICK (insn) = new_tick;
if (INSN_EXACT_TICK (insn) != INVALID_TICK
&& INSN_EXACT_TICK (insn) < clock_var + n_cycles)
{
must_backtrack = true;
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tcausing a backtrack.\n");
}
}
}
/* Remove INSN from queue. */
@ -1400,6 +1605,12 @@ ready_add (struct ready_list *ready, rtx insn, bool first_p)
gcc_assert (QUEUE_INDEX (insn) != QUEUE_READY);
QUEUE_INDEX (insn) = QUEUE_READY;
if (INSN_EXACT_TICK (insn) != INVALID_TICK
&& INSN_EXACT_TICK (insn) < clock_var)
{
must_backtrack = true;
}
}
/* Remove the element with the highest priority from the ready list and
@ -1546,9 +1757,6 @@ advance_one_cycle (void)
fprintf (sched_dump, ";;\tAdvanced a state.\n");
}
/* Clock at which the previous instruction was issued. */
static int last_clock_var;
/* Update register pressure after scheduling INSN. */
static void
update_register_pressure (rtx insn)
@ -1644,6 +1852,9 @@ struct sched_block_state
{
/* True if no real insns have been scheduled in the current cycle. */
bool first_cycle_insn_p;
/* True if a shadow insn has been scheduled in the current cycle, which
means that no more normal insns can be issued. */
bool shadows_only_p;
/* Initialized with the machine's issue rate every cycle, and updated
by calls to the variable_issue hook. */
int can_issue_more;
@ -1900,6 +2111,377 @@ remove_notes (rtx head, rtx tail)
}
}
/* A structure to record enough data to allow us to backtrack the scheduler to
a previous state. */
struct haifa_saved_data
{
/* Next entry on the list. */
struct haifa_saved_data *next;
/* Backtracking is associated with scheduling insns that have delay slots.
DELAY_PAIR points to the structure that contains the insns involved, and
the number of cycles between them. */
struct delay_pair *delay_pair;
/* Data used by the frontend (e.g. sched-ebb or sched-rgn). */
void *fe_saved_data;
/* Data used by the backend. */
void *be_saved_data;
/* Copies of global state. */
int clock_var, last_clock_var;
struct ready_list ready;
state_t curr_state;
rtx last_scheduled_insn;
rtx last_nondebug_scheduled_insn;
int cycle_issued_insns;
/* Copies of state used in the inner loop of schedule_block. */
struct sched_block_state sched_block;
/* We don't need to save q_ptr, as its value is arbitrary and we can set it
to 0 when restoring. */
int q_size;
rtx *insn_queue;
};
/* A record, in reverse order, of all scheduled insns which have delay slots
and may require backtracking. */
static struct haifa_saved_data *backtrack_queue;
/* For every dependency of INSN, set the FEEDS_BACKTRACK_INSN bit according
to SET_P. */
static void
mark_backtrack_feeds (rtx insn, int set_p)
{
sd_iterator_def sd_it;
dep_t dep;
FOR_EACH_DEP (insn, SD_LIST_HARD_BACK, sd_it, dep)
{
FEEDS_BACKTRACK_INSN (DEP_PRO (dep)) = set_p;
}
}
/* Make a copy of the INSN_LIST list LINK and return it. */
static rtx
copy_insn_list (rtx link)
{
rtx new_queue;
rtx *pqueue = &new_queue;
for (; link; link = XEXP (link, 1))
{
rtx x = XEXP (link, 0);
rtx newlink = alloc_INSN_LIST (x, NULL);
*pqueue = newlink;
pqueue = &XEXP (newlink, 1);
}
*pqueue = NULL_RTX;
return new_queue;
}
/* Save the current scheduler state so that we can backtrack to it
later if necessary. PAIR gives the insns that make it necessary to
save this point. SCHED_BLOCK is the local state of schedule_block
that need to be saved. */
static void
save_backtrack_point (struct delay_pair *pair,
struct sched_block_state sched_block)
{
int i;
struct haifa_saved_data *save = XNEW (struct haifa_saved_data);
save->curr_state = xmalloc (dfa_state_size);
memcpy (save->curr_state, curr_state, dfa_state_size);
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) = true;
pair = pair->next_same_i1;
}
}
/* 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)
{
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;
for (sd_it = sd_iterator_start (last, SD_LIST_RES_FORW);
sd_iterator_cond (&sd_it, &dep);)
{
rtx con = DEP_CON (dep);
TODO_SPEC (con) |= HARD_DEP;
INSN_TICK (con) = INVALID_TICK;
sd_unresolve_dep (sd_it);
}
if (last == insn)
break;
}
}
/* 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++)
{
QUEUE_INDEX (first[i]) = QUEUE_NOWHERE;
INSN_TICK (first[i]) = 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++)
{
QUEUE_INDEX (first[i]) = QUEUE_READY;
INSN_TICK (first[i]) = 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;
INSN_TICK (x) = save->clock_var + i;
}
}
free (save->insn_queue);
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 (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;
}
/* Return the head and tail pointers of ebb starting at BEG and ending
at END. */
@ -2467,11 +3049,6 @@ struct choice_entry
function max_issue. */
static struct choice_entry *choice_stack;
/* The following variable value is number of essential insns issued on
the current cycle. An insn is essential one if it changes the
processors state. */
int cycle_issued_insns;
/* This holds the value of the target dfa_lookahead hook. */
int dfa_lookahead;
@ -2884,10 +3461,18 @@ commit_schedule (rtx prev_head, rtx tail, basic_block *target_bb)
issued in this cycle. TEMP_STATE is temporary scheduler state we
can use as scratch space. If FIRST_CYCLE_INSN_P is true, no insns
have been issued for the current cycle, which means it is valid to
issue an asm statement. */
issue an asm statement.
If SHADOWS_ONLY_P is true, we eliminate all real insns and only
leave those for which SHADOW_P is true.
Return the number of cycles we must
advance to find the next ready instruction, or zero if there remain
insns on the ready list. */
static void
prune_ready_list (state_t temp_state, bool first_cycle_insn_p)
prune_ready_list (state_t temp_state, bool first_cycle_insn_p,
bool shadows_only_p)
{
int i;
@ -2898,7 +3483,12 @@ prune_ready_list (state_t temp_state, bool first_cycle_insn_p)
int cost = 0;
const char *reason = "resource conflict";
if (recog_memoized (insn) < 0)
if (shadows_only_p && !DEBUG_INSN_P (insn) && !SHADOW_P (insn))
{
cost = 1;
reason = "not a shadow";
}
else if (recog_memoized (insn) < 0)
{
if (!first_cycle_insn_p
&& (GET_CODE (PATTERN (insn)) == ASM_INPUT
@ -2910,12 +3500,34 @@ prune_ready_list (state_t temp_state, bool first_cycle_insn_p)
cost = 0;
else
{
int delay_cost = 0;
if (delay_htab)
{
struct delay_pair *delay_entry;
delay_entry
= (struct delay_pair *)htab_find_with_hash (delay_htab, insn,
htab_hash_pointer (insn));
while (delay_entry && delay_cost == 0)
{
delay_cost = estimate_shadow_tick (delay_entry);
if (delay_cost > max_insn_queue_index)
delay_cost = max_insn_queue_index;
delay_entry = delay_entry->next_same_i1;
}
}
memcpy (temp_state, curr_state, dfa_state_size);
cost = state_transition (temp_state, insn);
if (cost < 0)
cost = 0;
else if (cost == 0)
cost = 1;
if (cost < delay_cost)
{
cost = delay_cost;
reason = "shadow tick";
}
}
if (cost >= 1)
{
@ -2926,6 +3538,60 @@ prune_ready_list (state_t temp_state, bool first_cycle_insn_p)
}
}
/* Called when we detect that the schedule is impossible. We examine the
backtrack queue to find the earliest insn that caused this condition. */
static struct haifa_saved_data *
verify_shadows (void)
{
struct haifa_saved_data *save, *earliest_fail = NULL;
for (save = backtrack_queue; save; save = save->next)
{
int t;
struct delay_pair *pair = save->delay_pair;
rtx i1 = pair->i1;
for (; pair; pair = pair->next_same_i1)
{
rtx i2 = pair->i2;
if (QUEUE_INDEX (i2) == QUEUE_SCHEDULED)
continue;
t = INSN_TICK (i1) + pair_delay (pair);
if (t < clock_var)
{
if (sched_verbose >= 2)
fprintf (sched_dump,
";;\t\tfailed delay requirements for %d/%d (%d->%d)"
", not ready\n",
INSN_UID (pair->i1), INSN_UID (pair->i2),
INSN_TICK (pair->i1), INSN_EXACT_TICK (pair->i2));
earliest_fail = save;
break;
}
if (QUEUE_INDEX (i2) >= 0)
{
int queued_for = INSN_TICK (i2);
if (t < queued_for)
{
if (sched_verbose >= 2)
fprintf (sched_dump,
";;\t\tfailed delay requirements for %d/%d"
" (%d->%d), queued too late\n",
INSN_UID (pair->i1), INSN_UID (pair->i2),
INSN_TICK (pair->i1), INSN_EXACT_TICK (pair->i2));
earliest_fail = save;
break;
}
}
}
}
return earliest_fail;
}
/* Use forward list scheduling to rearrange insns of block pointed to by
TARGET_BB, possibly bringing insns from subsequent blocks in the same
region. */
@ -2955,6 +3621,8 @@ schedule_block (basic_block *target_bb)
haifa_recovery_bb_recently_added_p = false;
backtrack_queue = NULL;
/* Debug info. */
if (sched_verbose)
dump_new_block_header (0, *target_bb, head, tail);
@ -3051,6 +3719,8 @@ schedule_block (basic_block *target_bb)
gcc_assert (VEC_length (rtx, scheduled_insns) == 0);
sort_p = TRUE;
must_backtrack = false;
/* Loop until all the insns in BB are scheduled. */
while ((*current_sched_info->schedule_more_p) ())
{
@ -3080,18 +3750,21 @@ schedule_block (basic_block *target_bb)
while (advance > 0);
if (ready.n_ready > 0)
prune_ready_list (temp_state, true);
prune_ready_list (temp_state, true, false);
if (ready.n_ready == 0)
continue;
if (must_backtrack)
goto do_backtrack;
ls.first_cycle_insn_p = true;
ls.shadows_only_p = false;
cycle_issued_insns = 0;
ls.can_issue_more = issue_rate;
for (;;)
{
rtx insn;
int cost;
bool asm_p = false;
bool asm_p;
if (sort_p && ready.n_ready > 0)
{
@ -3130,6 +3803,7 @@ schedule_block (basic_block *target_bb)
if (ls.first_cycle_insn_p && !ready.n_ready)
break;
resume_after_backtrack:
/* Allow the target to reorder the list, typically for
better instruction bundling. */
if (sort_p
@ -3236,6 +3910,22 @@ schedule_block (basic_block *target_bb)
goto restart_choose_ready;
}
if (delay_htab)
{
/* If this insn is the first part of a delay-slot pair, record a
backtrack point. */
struct delay_pair *delay_entry;
delay_entry
= (struct delay_pair *)htab_find_with_hash (delay_htab, insn,
htab_hash_pointer (insn));
if (delay_entry)
{
save_backtrack_point (delay_entry, ls);
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tsaving backtrack point\n");
}
}
/* DECISION is made. */
if (TODO_SPEC (insn) & SPECULATIVE)
@ -3275,18 +3965,70 @@ schedule_block (basic_block *target_bb)
ls.can_issue_more--;
advance = schedule_insn (insn);
if (SHADOW_P (insn))
ls.shadows_only_p = true;
/* After issuing an asm insn we should start a new cycle. */
if (advance == 0 && asm_p)
advance = 1;
if (must_backtrack)
break;
if (advance != 0)
break;
ls.first_cycle_insn_p = false;
if (ready.n_ready > 0)
prune_ready_list (temp_state, false);
prune_ready_list (temp_state, false, ls.shadows_only_p);
}
do_backtrack:
if (!must_backtrack)
for (i = 0; i < ready.n_ready; i++)
{
rtx insn = ready_element (&ready, i);
if (INSN_EXACT_TICK (insn) == clock_var)
{
must_backtrack = true;
clock_var++;
break;
}
}
while (must_backtrack)
{
struct haifa_saved_data *failed;
rtx failed_insn;
must_backtrack = false;
failed = verify_shadows ();
gcc_assert (failed);
failed_insn = failed->delay_pair->i1;
unschedule_insns_until (failed_insn);
while (failed != backtrack_queue)
free_topmost_backtrack_point (true);
restore_last_backtrack_point (&ls);
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\trewind to cycle %d\n", clock_var);
/* Delay by at least a cycle. This could cause additional
backtracking. */
queue_insn (failed_insn, 1, "backtracked");
advance = 0;
if (must_backtrack)
continue;
if (ready.n_ready > 0)
goto resume_after_backtrack;
else
{
if (clock_var == 0 && ls.first_cycle_insn_p)
goto end_schedule;
advance = 1;
break;
}
}
}
end_schedule:
/* Debug info. */
if (sched_verbose)
{
@ -3364,6 +4106,8 @@ schedule_block (basic_block *target_bb)
current_sched_info->head = head;
current_sched_info->tail = tail;
free_backtrack_queue ();
}
/* Set_priorities: compute priority of each insn in the block. */
@ -3488,7 +4232,8 @@ sched_init (void)
init_alias_analysis ();
df_set_flags (DF_LR_RUN_DCE);
if (!sched_no_dce)
df_set_flags (DF_LR_RUN_DCE);
df_note_add_problem ();
/* More problems needed for interloop dep calculation in SMS. */
@ -3653,6 +4398,17 @@ sched_finish (void)
#endif
}
/* Free all delay_pair structures that were recorded. */
void
free_delay_pairs (void)
{
if (delay_htab)
{
htab_empty (delay_htab);
htab_empty (delay_htab_i2);
}
}
/* Fix INSN_TICKs of the instructions in the current block as well as
INSN_TICKs of their dependents.
HEAD and TAIL are the begin and the end of the current scheduled block. */
@ -5453,6 +6209,7 @@ init_h_i_d (rtx insn)
INSN_COST (insn) = -1;
QUEUE_INDEX (insn) = QUEUE_NOWHERE;
INSN_TICK (insn) = INVALID_TICK;
INSN_EXACT_TICK (insn) = INVALID_TICK;
INTER_TICK (insn) = INVALID_TICK;
TODO_SPEC (insn) = HARD_DEP;
}

View File

@ -283,6 +283,7 @@ static struct haifa_sched_info sms_sched_info =
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL,
0
};

View File

@ -1301,6 +1301,28 @@ sd_resolve_dep (sd_iterator_def sd_it)
INSN_RESOLVED_FORW_DEPS (pro));
}
/* Perform the inverse operation of sd_resolve_dep. Restore the dependence
pointed to by SD_IT to unresolved state. */
void
sd_unresolve_dep (sd_iterator_def sd_it)
{
dep_node_t node = DEP_LINK_NODE (*sd_it.linkp);
dep_t dep = DEP_NODE_DEP (node);
rtx pro = DEP_PRO (dep);
rtx con = DEP_CON (dep);
if ((current_sched_info->flags & DO_SPECULATION)
&& (DEP_STATUS (dep) & SPECULATIVE))
move_dep_link (DEP_NODE_BACK (node), INSN_RESOLVED_BACK_DEPS (con),
INSN_SPEC_BACK_DEPS (con));
else
move_dep_link (DEP_NODE_BACK (node), INSN_RESOLVED_BACK_DEPS (con),
INSN_HARD_BACK_DEPS (con));
move_dep_link (DEP_NODE_FORW (node), INSN_RESOLVED_FORW_DEPS (pro),
INSN_FORW_DEPS (pro));
}
/* Make TO depend on all the FROM's producers.
If RESOLVED_P is true add dependencies to the resolved lists. */
void

View File

@ -74,6 +74,25 @@ static void ebb_add_block (basic_block, basic_block);
static basic_block advance_target_bb (basic_block, rtx);
static void ebb_fix_recovery_cfg (int, int, int);
/* Allocate memory and store the state of the frontend. Return the allocated
memory. */
static void *
save_ebb_state (void)
{
int *p = XNEW (int);
*p = sched_rgn_n_insns;
return p;
}
/* Restore the state of the frontend from P_, then free it. */
static void
restore_ebb_state (void *p_)
{
int *p = (int *)p_;
sched_rgn_n_insns = *p;
free (p_);
}
/* Return nonzero if there are more insns that should be scheduled. */
static int
@ -295,6 +314,10 @@ static struct haifa_sched_info ebb_sched_info =
begin_schedule_ready,
begin_move_insn,
advance_target_bb,
save_ebb_state,
restore_ebb_state,
SCHED_EBB
/* We can create new blocks in begin_schedule_ready (). */
| NEW_BBS
@ -377,76 +400,80 @@ add_deps_for_risky_insns (rtx head, rtx tail)
basic_block last_block = NULL, bb;
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
if (control_flow_insn_p (insn))
{
bb = BLOCK_FOR_INSN (insn);
bb->aux = last_block;
last_block = bb;
last_jump = insn;
}
else if (INSN_P (insn) && last_jump != NULL_RTX)
{
classification = haifa_classify_insn (insn);
prev = last_jump;
switch (classification)
{
case PFREE_CANDIDATE:
if (flag_schedule_speculative_load)
{
bb = earliest_block_with_similiar_load (last_block, insn);
if (bb)
{
bb = (basic_block) bb->aux;
if (!bb)
break;
prev = BB_END (bb);
}
}
/* Fall through. */
case TRAP_RISKY:
case IRISKY:
case PRISKY_CANDIDATE:
/* ??? We could implement better checking PRISKY_CANDIDATEs
analogous to sched-rgn.c. */
/* We can not change the mode of the backward
dependency because REG_DEP_ANTI has the lowest
rank. */
if (! sched_insns_conditions_mutex_p (insn, prev))
{
dep_def _dep, *dep = &_dep;
{
add_delay_dependencies (insn);
if (control_flow_insn_p (insn))
{
bb = BLOCK_FOR_INSN (insn);
bb->aux = last_block;
last_block = bb;
last_jump = insn;
}
else if (INSN_P (insn) && last_jump != NULL_RTX)
{
classification = haifa_classify_insn (insn);
prev = last_jump;
init_dep (dep, prev, insn, REG_DEP_ANTI);
switch (classification)
{
case PFREE_CANDIDATE:
if (flag_schedule_speculative_load)
{
bb = earliest_block_with_similiar_load (last_block, insn);
if (bb)
{
bb = (basic_block) bb->aux;
if (!bb)
break;
prev = BB_END (bb);
}
}
/* Fall through. */
case TRAP_RISKY:
case IRISKY:
case PRISKY_CANDIDATE:
/* ??? We could implement better checking PRISKY_CANDIDATEs
analogous to sched-rgn.c. */
/* We can not change the mode of the backward
dependency because REG_DEP_ANTI has the lowest
rank. */
if (! sched_insns_conditions_mutex_p (insn, prev))
{
dep_def _dep, *dep = &_dep;
if (!(current_sched_info->flags & USE_DEPS_LIST))
{
enum DEPS_ADJUST_RESULT res;
init_dep (dep, prev, insn, REG_DEP_ANTI);
res = sd_add_or_update_dep (dep, false);
if (!(current_sched_info->flags & USE_DEPS_LIST))
{
enum DEPS_ADJUST_RESULT res;
/* We can't change an existing dependency with
DEP_ANTI. */
gcc_assert (res != DEP_CHANGED);
}
else
{
if ((current_sched_info->flags & DO_SPECULATION)
&& (spec_info->mask & BEGIN_CONTROL))
DEP_STATUS (dep) = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
MAX_DEP_WEAK);
res = sd_add_or_update_dep (dep, false);
sd_add_or_update_dep (dep, false);
/* We can't change an existing dependency with
DEP_ANTI. */
gcc_assert (res != DEP_CHANGED);
}
else
{
if ((current_sched_info->flags & DO_SPECULATION)
&& (spec_info->mask & BEGIN_CONTROL))
DEP_STATUS (dep) = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
MAX_DEP_WEAK);
/* Dep_status could have been changed.
No assertion here. */
}
}
sd_add_or_update_dep (dep, false);
break;
/* Dep_status could have been changed.
No assertion here. */
}
}
default:
break;
}
}
break;
default:
break;
}
}
}
/* Maintain the invariant that bb->aux is clear after use. */
while (last_block)
{

View File

@ -603,6 +603,13 @@ struct haifa_sched_info
The first parameter is the current basic block in EBB. */
basic_block (*advance_target_bb) (basic_block, rtx);
/* Allocate memory, store the frontend scheduler state in it, and
return it. */
void *(*save_state) (void);
/* Restore frontend scheduler state from the argument, and free the
memory. */
void (*restore_state) (void *);
/* ??? FIXME: should use straight bitfields inside sched_info instead of
this flag field. */
unsigned int flags;
@ -762,10 +769,18 @@ struct _haifa_insn_data
used to note timing constraints for the insns in the pending list. */
int tick;
/* For insns that are scheduled at a fixed difference from another,
this records the tick in which they must be ready. */
int exact_tick;
/* INTER_TICK is used to adjust INSN_TICKs of instructions from the
subsequent blocks in a region. */
int inter_tick;
/* Used temporarily to estimate an INSN_TICK value for an insn given
current knowledge. */
int tick_estimate;
/* See comment on QUEUE_INDEX macro in haifa-sched.c. */
int queue_index;
@ -775,6 +790,14 @@ struct _haifa_insn_data
moved load insn and this one. */
unsigned int fed_by_spec_load : 1;
unsigned int is_load_insn : 1;
/* Nonzero if this insn has negative-cost forward dependencies against
an already scheduled insn. */
unsigned int feeds_backtrack_insn : 1;
/* Nonzero if this insn is a shadow of another, scheduled after a fixed
delay. We only emit shadows at the end of a cycle, with no other
real insns following them. */
unsigned int shadow_p : 1;
/* '> 0' if priority is valid,
'== 0' if priority was not yet computed,
@ -1017,7 +1040,8 @@ enum SCHED_FLAGS {
Results in generation of data and control speculative dependencies.
Requires USE_DEPS_LIST set. */
DO_SPECULATION = USE_DEPS_LIST << 1,
SCHED_RGN = DO_SPECULATION << 1,
DO_BACKTRACKING = DO_SPECULATION << 1,
SCHED_RGN = DO_BACKTRACKING << 1,
SCHED_EBB = SCHED_RGN << 1,
/* Scheduler can possibly create new basic blocks. Used for assertions. */
NEW_BBS = SCHED_EBB << 1,
@ -1304,7 +1328,11 @@ extern int *ebb_head;
extern int current_nr_blocks;
extern int current_blocks;
extern int target_bb;
extern bool sched_no_dce;
extern void record_delay_slot_pair (rtx, rtx, int);
extern void free_delay_pairs (void);
extern void add_delay_dependencies (rtx);
extern bool sched_is_disabled_for_current_region_p (void);
extern void sched_rgn_init (bool);
extern void sched_rgn_finish (void);
@ -1478,6 +1506,7 @@ extern dep_t sd_find_dep_between (rtx, rtx, bool);
extern void sd_add_dep (dep_t, bool);
extern enum DEPS_ADJUST_RESULT sd_add_or_update_dep (dep_t, bool);
extern void sd_resolve_dep (sd_iterator_def);
extern void sd_unresolve_dep (sd_iterator_def);
extern void sd_copy_back_deps (rtx, rtx, bool);
extern void sd_delete_dep (sd_iterator_def);
extern void sd_debug_lists (rtx, sd_list_types_def);

View File

@ -2371,6 +2371,7 @@ static const struct haifa_sched_info rgn_const_sched_info =
begin_schedule_ready,
NULL,
advance_target_bb,
NULL, NULL,
SCHED_RGN
};

View File

@ -5700,6 +5700,10 @@ static struct haifa_sched_info sched_sel_haifa_sched_info =
NULL, /* begin_schedule_ready */
NULL, /* begin_move_insn */
NULL, /* advance_target_bb */
NULL,
NULL,
SEL_SCHED | NEW_BBS
};