/* Instruction scheduling pass. This file computes dependencies between
instructions.
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 1992-2014 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
and currently maintained by, Jim Wilson (wilson@cygnus.com)
struct sched_deps_info_def *sched_deps_info;
/* The data is specific to the Haifa scheduler. */
-VEC(haifa_deps_insn_data_def, heap) *h_d_i_d = NULL;
+vec<haifa_deps_insn_data_def>
+ h_d_i_d = vNULL;
/* Return the major type present in the DS. */
enum reg_note
gcc_assert (dep_link_is_detached_p (DEP_NODE_BACK (n))
&& dep_link_is_detached_p (DEP_NODE_FORW (n)));
+ XDELETE (DEP_REPLACE (DEP_NODE_DEP (n)));
+
--dn_pool_diff;
pool_free (dn_pool, n);
return use;
}
-/* Allocate and return reg_set_data structure for REGNO and INSN. */
-static struct reg_set_data *
+/* Allocate reg_set_data structure for REGNO and INSN. */
+static void
create_insn_reg_set (int regno, rtx insn)
{
struct reg_set_data *set;
set->insn = insn;
set->next_insn_set = INSN_REG_SET_LIST (insn);
INSN_REG_SET_LIST (insn) = set;
- return set;
}
/* Set up insn register uses for INSN and dependency context DEPS. */
/* Always add these dependencies to pending_reads, since
this insn may be followed by a write. */
- if (!deps->readonly)
- add_insn_mem_dependence (deps, true, insn, x);
+ if (!deps->readonly)
+ {
+ if ((deps->pending_read_list_length
+ + deps->pending_write_list_length)
+ > MAX_PENDING_LIST_LENGTH
+ && !DEBUG_INSN_P (insn))
+ flush_pending_lists (deps, insn, true, true);
+ add_insn_mem_dependence (deps, true, insn, x);
+ }
sched_analyze_2 (deps, XEXP (x, 0), insn);
case PREFETCH:
if (PREFETCH_SCHEDULE_BARRIER_P (x))
reg_pending_barrier = TRUE_BARRIER;
+ /* Prefetch insn contains addresses only. So if the prefetch
+ address has no registers, there will be no dependencies on
+ the prefetch insn. This is wrong with result code
+ correctness point of view as such prefetch can be moved below
+ a jump insn which usually generates MOVE_BARRIER preventing
+ to move insns containing registers or memories through the
+ barrier. It is also wrong with generated code performance
+ point of view as prefetch withouth dependecies will have a
+ tendency to be issued later instead of earlier. It is hard
+ to generate accurate dependencies for prefetch insns as
+ prefetch has only the start address but it is better to have
+ something than nothing. */
+ if (!deps->readonly)
+ {
+ rtx x = gen_rtx_MEM (Pmode, XEXP (PATTERN (insn), 0));
+ if (sched_deps_info->use_cselib)
+ cselib_lookup_from_insn (x, Pmode, true, VOIDmode, insn);
+ add_insn_mem_dependence (deps, true, insn, x);
+ }
break;
case UNSPEC_VOLATILE:
Consider for instance a volatile asm that changes the fpu rounding
mode. An insn should not be moved across this even if it only uses
pseudo-regs because it might give an incorrectly rounded result. */
- if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
+ if ((code != ASM_OPERANDS || MEM_VOLATILE_P (x))
+ && !DEBUG_INSN_P (insn))
reg_pending_barrier = TRUE_BARRIER;
/* For all ASM_OPERANDS, we must traverse the vector of input operands.
sched_deps_info->finish_rhs ();
}
+/* Try to group comparison and the following conditional jump INSN if
+ they're already adjacent. This is to prevent scheduler from scheduling
+ them apart. */
+
+static void
+try_group_insn (rtx insn)
+{
+ unsigned int condreg1, condreg2;
+ rtx cc_reg_1;
+ rtx prev;
+
+ if (!any_condjump_p (insn))
+ return;
+
+ targetm.fixed_condition_code_regs (&condreg1, &condreg2);
+ cc_reg_1 = gen_rtx_REG (CCmode, condreg1);
+ prev = prev_nonnote_nondebug_insn (insn);
+ if (!reg_referenced_p (cc_reg_1, PATTERN (insn))
+ || !prev
+ || !modified_in_p (cc_reg_1, prev))
+ return;
+
+ /* Different microarchitectures support macro fusions for different
+ combinations of insn pairs. */
+ if (!targetm.sched.macro_fusion_pair_p
+ || !targetm.sched.macro_fusion_pair_p (prev, insn))
+ return;
+
+ SCHED_GROUP_P (insn) = 1;
+}
+
/* Analyze an INSN with pattern X to find all dependencies. */
static void
sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
HARD_REG_SET temp;
extract_insn (insn);
- preprocess_constraints ();
+ preprocess_constraints (insn);
ira_implicitly_set_insn_hard_regs (&temp);
AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
IOR_HARD_REG_SET (implicit_reg_pending_clobbers, temp);
can_start_lhs_rhs_p = (NONJUMP_INSN_P (insn)
&& code == SET);
+ /* Group compare and branch insns for macro-fusion. */
+ if (targetm.sched.macro_fusion_p
+ && targetm.sched.macro_fusion_p ())
+ try_group_insn (insn);
+
if (may_trap_p (x))
/* Avoid moving trapping instructions across function calls that might
not always return. */
SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
}
- /* Flush pending lists on jumps, but not on speculative checks. */
- if (JUMP_P (insn) && !(sel_sched_p ()
- && sel_insn_is_speculation_check (insn)))
+ /* Don't flush pending lists on speculative checks for
+ selective scheduling. */
+ if (!sel_sched_p () || !sel_insn_is_speculation_check (insn))
flush_pending_lists (deps, insn, true, true);
reg_pending_barrier = NOT_A_BARRIER;
change_spec_dep_to_hard (sd_it);
}
}
+
+ /* We do not yet have code to adjust REG_ARGS_SIZE, therefore we must
+ honor their original ordering. */
+ if (find_reg_note (insn, REG_ARGS_SIZE, NULL))
+ {
+ if (deps->last_args_size)
+ add_dependence (insn, deps->last_args_size, REG_DEP_OUTPUT);
+ deps->last_args_size = insn;
+ }
}
/* Return TRUE if INSN might not always return normally (e.g. call exit,
if (sched_deps_info->use_cselib)
cselib_process_insn (insn);
- /* EH_REGION insn notes can not appear until well after we complete
- scheduling. */
- if (NOTE_P (insn))
- gcc_assert (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
- && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END);
-
if (sched_deps_info->finish_insn)
sched_deps_info->finish_insn ();
{
/* And initialize deps_lists. */
sd_init_insn (insn);
+ /* Clean up SCHED_GROUP_P which may be set by last
+ scheduler pass. */
+ if (SCHED_GROUP_P (insn))
+ SCHED_GROUP_P (insn) = 0;
}
deps_analyze_insn (deps, insn);
deps->sched_before_next_jump = 0;
deps->in_post_call_group_p = not_post_call;
deps->last_debug_insn = 0;
+ deps->last_args_size = 0;
deps->last_reg_pending_barrier = NOT_A_BARRIER;
deps->readonly = 0;
}
static void
init_deps_data_vector (void)
{
- int reserve = (sched_max_luid + 1
- - VEC_length (haifa_deps_insn_data_def, h_d_i_d));
- if (reserve > 0
- && ! VEC_space (haifa_deps_insn_data_def, h_d_i_d, reserve))
- VEC_safe_grow_cleared (haifa_deps_insn_data_def, heap, h_d_i_d,
- 3 * sched_max_luid / 2);
+ int reserve = (sched_max_luid + 1 - h_d_i_d.length ());
+ if (reserve > 0 && ! h_d_i_d.space (reserve))
+ h_d_i_d.safe_grow_cleared (3 * sched_max_luid / 2);
}
/* If it is profitable to use them, initialize or extend (depending on
{
/* Average number of insns in the basic block.
'+ 1' is used to make it nonzero. */
- int insns_in_block = sched_max_luid / n_basic_blocks + 1;
+ int insns_in_block = sched_max_luid / n_basic_blocks_for_fn (cfun) + 1;
init_deps_data_vector ();
free_alloc_pool_if_empty (&dl_pool);
gcc_assert (dn_pool == NULL && dl_pool == NULL);
- VEC_free (haifa_deps_insn_data_def, heap, h_d_i_d);
+ h_d_i_d.release ();
cache_size = 0;
if (true_dependency_cache)
cur_insn = NULL;
}
-/* Return weakness of speculative type TYPE in the dep_status DS. */
-dw_t
+/* Return weakness of speculative type TYPE in the dep_status DS,
+ without checking to prevent ICEs on malformed input. */
+static dw_t
get_dep_weak_1 (ds_t ds, ds_t type)
{
ds = ds & type;
return (dw_t) ds;
}
+/* Return weakness of speculative type TYPE in the dep_status DS. */
dw_t
get_dep_weak (ds_t ds, ds_t type)
{
rtx mem = *mii->mem_loc;
rtx new_mem;
- /* Jump thru a lot of hoops to keep the attributes up to date. We
+ /* Jump through a lot of hoops to keep the attributes up to date. We
do not want to call one of the change address variants that take
an offset even though we know the offset in many cases. These
assume you are changing where the address is pointing by the
if (parse_add_or_inc (mii, inc_cand, backwards))
{
struct dep_replacement *desc;
- df_ref *def_rec;
+ df_ref def;
rtx newaddr, newmem;
if (sched_verbose >= 5)
/* Need to assure that none of the operands of the inc
instruction are assigned to by the mem insn. */
- for (def_rec = DF_INSN_DEFS (mii->mem_insn); *def_rec; def_rec++)
- {
- df_ref def = *def_rec;
- if (reg_overlap_mentioned_p (DF_REF_REG (def), mii->inc_input)
- || reg_overlap_mentioned_p (DF_REF_REG (def), mii->mem_reg0))
- {
- if (sched_verbose >= 5)
- fprintf (sched_dump,
- "inc conflicts with store failure.\n");
- goto next;
- }
- }
+ FOR_EACH_INSN_DEF (def, mii->mem_insn)
+ if (reg_overlap_mentioned_p (DF_REF_REG (def), mii->inc_input)
+ || reg_overlap_mentioned_p (DF_REF_REG (def), mii->mem_reg0))
+ {
+ if (sched_verbose >= 5)
+ fprintf (sched_dump,
+ "inc conflicts with store failure.\n");
+ goto next;
+ }
newaddr = mii->inc_input;
if (mii->mem_index != NULL_RTX)
newaddr = gen_rtx_PLUS (GET_MODE (newaddr), newaddr,
}
if (REG_P (reg0))
{
- df_ref *def_rec;
+ df_ref use;
int occurrences = 0;
/* Make sure this reg appears only once in this insn. Can't use
count_occurrences since that only works for pseudos. */
- for (def_rec = DF_INSN_USES (mii->mem_insn); *def_rec; def_rec++)
- {
- df_ref def = *def_rec;
- if (reg_overlap_mentioned_p (reg0, DF_REF_REG (def)))
- if (++occurrences > 1)
- {
- if (sched_verbose >= 5)
- fprintf (sched_dump, "mem count failure\n");
- return false;
- }
- }
+ FOR_EACH_INSN_USE (use, mii->mem_insn)
+ if (reg_overlap_mentioned_p (reg0, DF_REF_REG (use)))
+ if (++occurrences > 1)
+ {
+ if (sched_verbose >= 5)
+ fprintf (sched_dump, "mem count failure\n");
+ return false;
+ }
mii->mem_reg0 = reg0;
return find_inc (mii, true) || find_inc (mii, false);