/* Instruction scheduling pass. Selective scheduler and pipeliner.
- Copyright (C) 2006-2014 Free Software Foundation, Inc.
+ Copyright (C) 2006-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "hard-reg-set.h"
#include "regs.h"
#include "function.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgbuild.h"
+#include "basic-block.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "target.h"
#include "output.h"
#include "sched-int.h"
-#include "ggc.h"
+#include "symtab.h"
#include "tree.h"
-#include "vec.h"
#include "langhooks.h"
#include "rtlhooks-def.h"
#include "emit-rtl.h"
#include "ira.h"
+#include "rtl-iter.h"
#ifdef INSN_SCHEDULING
#include "sel-sched-ir.h"
{
unsigned i;
int cycle;
- rtx insn;
+ rtx_insn *insn;
advance_state (FENCE_STATE (fence));
cycle = ++FENCE_CYCLE (fence);
/* Returns true when SUCC in a fallthru bb of INSN, possibly
skipping empty basic blocks. */
static bool
-in_fallthru_bb_p (rtx insn, rtx succ)
+in_fallthru_bb_p (rtx_insn *insn, rtx succ)
{
basic_block bb = BLOCK_FOR_INSN (insn);
edge e;
int orig_max_seqno)
{
bool was_here_p = false;
- insn_t insn = NULL_RTX;
+ insn_t insn = NULL;
insn_t succ;
succ_iterator si;
ilist_iterator ii;
/* Substitute if INSN has a form of x:=y and LHS(INSN) occurs in *VI. */
if (rtx_ok_for_substitution_p (old, *where))
{
- rtx new_insn;
+ rtx_insn *new_insn;
rtx *where_replace;
/* We should copy these rtxes before substitution. */
return false;
}
-/* Helper function for count_occurences_equiv. */
-static int
-count_occurrences_1 (rtx *cur_rtx, void *arg)
-{
- rtx_search_arg_p p = (rtx_search_arg_p) arg;
-
- if (REG_P (*cur_rtx) && REGNO (*cur_rtx) == REGNO (p->x))
- {
- /* Bail out if mode is different or more than one register is used. */
- if (GET_MODE (*cur_rtx) != GET_MODE (p->x)
- || (HARD_REGISTER_P (*cur_rtx)
- && hard_regno_nregs[REGNO (*cur_rtx)][GET_MODE (*cur_rtx)] > 1))
- {
- p->n = 0;
- return 1;
- }
-
- p->n++;
-
- /* Do not traverse subexprs. */
- return -1;
- }
-
- if (GET_CODE (*cur_rtx) == SUBREG
- && (!REG_P (SUBREG_REG (*cur_rtx))
- || REGNO (SUBREG_REG (*cur_rtx)) == REGNO (p->x)))
- {
- /* ??? Do not support substituting regs inside subregs. In that case,
- simplify_subreg will be called by validate_replace_rtx, and
- unsubstitution will fail later. */
- p->n = 0;
- return 1;
- }
-
- /* Continue search. */
- return 0;
-}
-
/* Return the number of places WHAT appears within WHERE.
Bail out when we found a reference occupying several hard registers. */
static int
-count_occurrences_equiv (rtx what, rtx where)
+count_occurrences_equiv (const_rtx what, const_rtx where)
{
- struct rtx_search_arg arg;
-
- gcc_assert (REG_P (what));
- arg.x = what;
- arg.n = 0;
-
- for_each_rtx (&where, &count_occurrences_1, (void *) &arg);
-
- return arg.n;
+ int count = 0;
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, where, NONCONST)
+ {
+ const_rtx x = *iter;
+ if (REG_P (x) && REGNO (x) == REGNO (what))
+ {
+ /* Bail out if mode is different or more than one register is
+ used. */
+ if (GET_MODE (x) != GET_MODE (what) || REG_NREGS (x) > 1)
+ return 0;
+ count += 1;
+ }
+ else if (GET_CODE (x) == SUBREG
+ && (!REG_P (SUBREG_REG (x))
+ || REGNO (SUBREG_REG (x)) == REGNO (what)))
+ /* ??? Do not support substituting regs inside subregs. In that case,
+ simplify_subreg will be called by validate_replace_rtx, and
+ unsubstitution will fail later. */
+ return 0;
+ }
+ return count;
}
/* Returns TRUE if WHAT is found in WHERE rtx tree. */
/* Substitute VI's set source with REGNO. Returns newly created pattern
that has REGNO as its source. */
-static rtx
+static rtx_insn *
create_insn_rtx_with_rhs (vinsn_t vi, rtx rhs_rtx)
{
rtx lhs_rtx;
rtx pattern;
- rtx insn_rtx;
+ rtx_insn *insn_rtx;
lhs_rtx = copy_rtx (VINSN_LHS (vi));
- pattern = gen_rtx_SET (VOIDmode, lhs_rtx, rhs_rtx);
+ pattern = gen_rtx_SET (lhs_rtx, rhs_rtx);
insn_rtx = create_insn_rtx_from_pattern (pattern, NULL_RTX);
return insn_rtx;
replace_src_with_reg_ok_p (insn_t insn, rtx new_src_reg)
{
vinsn_t vi = INSN_VINSN (insn);
- enum machine_mode mode;
+ machine_mode mode;
rtx dst_loc;
bool res;
}
/* Create a pattern with rhs of VI and lhs of LHS_RTX. */
-static rtx
+static rtx_insn *
create_insn_rtx_with_lhs (vinsn_t vi, rtx lhs_rtx)
{
rtx rhs_rtx;
rtx pattern;
- rtx insn_rtx;
+ rtx_insn *insn_rtx;
rhs_rtx = copy_rtx (VINSN_RHS (vi));
- pattern = gen_rtx_SET (VOIDmode, lhs_rtx, rhs_rtx);
+ pattern = gen_rtx_SET (lhs_rtx, rhs_rtx);
insn_rtx = create_insn_rtx_from_pattern (pattern, NULL_RTX);
return insn_rtx;
static void
replace_dest_with_reg_in_expr (expr_t expr, rtx new_reg)
{
- rtx insn_rtx;
+ rtx_insn *insn_rtx;
vinsn_t vinsn;
insn_rtx = create_insn_rtx_with_lhs (EXPR_VINSN (expr), new_reg);
Code adopted from regrename.c::build_def_use. */
static enum reg_class
-get_reg_class (rtx insn)
+get_reg_class (rtx_insn *insn)
{
int i, n_ops;
- extract_insn (insn);
- if (! constrain_operands (1))
- fatal_insn_not_found (insn);
+ extract_constrain_insn (insn);
preprocess_constraints (insn);
n_ops = recog_data.n_operands;
return NO_REGS;
}
-#ifdef HARD_REGNO_RENAME_OK
/* Calculate HARD_REGNO_RENAME_OK data for REGNO. */
static void
init_hard_regno_rename (int regno)
SET_HARD_REG_BIT (sel_hrd.regs_for_rename[regno], cur_reg);
}
}
-#endif
/* A wrapper around HARD_REGNO_RENAME_OK that will look into the hard regs
data first. */
static inline bool
sel_hard_regno_rename_ok (int from ATTRIBUTE_UNUSED, int to ATTRIBUTE_UNUSED)
{
-#ifdef HARD_REGNO_RENAME_OK
/* Check whether this is all calculated. */
if (TEST_HARD_REG_BIT (sel_hrd.regs_for_rename[from], from))
return TEST_HARD_REG_BIT (sel_hrd.regs_for_rename[from], to);
init_hard_regno_rename (from);
return TEST_HARD_REG_BIT (sel_hrd.regs_for_rename[from], to);
-#else
- return true;
-#endif
}
/* Calculate set of registers that are capable of holding MODE. */
static void
-init_regs_for_mode (enum machine_mode mode)
+init_regs_for_mode (machine_mode mode)
{
int cur_reg;
mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
regset used_regs ATTRIBUTE_UNUSED)
{
- enum machine_mode mode;
+ machine_mode mode;
enum reg_class cl = NO_REGS;
rtx orig_dest;
unsigned cur_reg, regno;
{
int best_new_reg;
unsigned cur_reg;
- enum machine_mode mode = VOIDmode;
+ machine_mode mode = VOIDmode;
unsigned regno, i, n;
hard_reg_set_iterator hrsi;
def_list_iterator di;
{
def_list_iterator i;
def_t def;
- enum machine_mode mode = VOIDmode;
+ machine_mode mode = VOIDmode;
bool bad_hard_regs = false;
/* We should not use this after reload. */
struct reg_rename *reg_rename_p)
{
unsigned n, i, regno;
- enum machine_mode mode;
+ machine_mode mode;
bool target_available, live_available, hard_available;
if (!REG_P (EXPR_LHS (expr)) || EXPR_TARGET_AVAILABLE (expr) < 0)
create_speculation_check (expr_t c_expr, ds_t check_ds, insn_t orig_insn)
{
rtx check_pattern;
- rtx insn_rtx;
+ rtx_insn *insn_rtx;
insn_t insn;
basic_block recovery_block;
- rtx label;
+ rtx_insn *label;
/* Create a recovery block if target is going to emit branchy check, or if
ORIG_INSN was speculative already. */
else
{
recovery_block = NULL;
- label = NULL_RTX;
+ label = NULL;
}
/* Get pattern of the check. */
/* True when INSN is a "regN = regN" copy. */
static bool
-identical_copy_p (rtx insn)
+identical_copy_p (rtx_insn *insn)
{
rtx lhs, rhs, pat;
/* Undo all transformations on *AV_PTR that were done when
moving through INSN. */
static void
-undo_transformations (av_set_t *av_ptr, rtx insn)
+undo_transformations (av_set_t *av_ptr, rtx_insn *insn)
{
av_set_iterator av_iter;
expr_t expr;
implicit_clobber_conflict_p (insn_t through_insn, expr_t expr)
{
HARD_REG_SET temp;
- rtx insn, reg, rhs, pat;
+ rtx_insn *insn;
+ rtx reg, rhs, pat;
hard_reg_set_iterator hrsi;
unsigned regno;
bool valid;
/* Make a new insn with it. */
rhs = copy_rtx (VINSN_RHS (EXPR_VINSN (expr)));
- pat = gen_rtx_SET (VOIDmode, reg, rhs);
+ pat = gen_rtx_SET (reg, rhs);
start_sequence ();
insn = emit_insn (pat);
end_sequence ();
/* Update liveness sets for INSN. */
static inline void
-update_liveness_on_insn (rtx insn)
+update_liveness_on_insn (rtx_insn *insn)
{
ignore_first = true;
compute_live (insn);
/* Compute liveness below INSN and write it into REGS. */
static inline void
-compute_live_below_insn (rtx insn, regset regs)
+compute_live_below_insn (rtx_insn *insn, regset regs)
{
- rtx succ;
+ rtx_insn *succ;
succ_iterator si;
FOR_EACH_SUCC_1 (succ, si, insn, SUCCS_ALL)
/* Update the data gathered in av and lv sets starting from INSN. */
static void
-update_data_sets (rtx insn)
+update_data_sets (rtx_insn *insn)
{
update_liveness_on_insn (insn);
if (sel_bb_head_p (insn))
if (FENCE_SCHED_NEXT (fence))
{
gcc_assert (sched_next_worked == 1);
- FENCE_SCHED_NEXT (fence) = NULL_RTX;
+ FENCE_SCHED_NEXT (fence) = NULL;
}
/* No need to stall if this variable was not initialized. */
if (issue_more && ran_hook)
{
int i, j, n;
- rtx *arr = ready.vec;
+ rtx_insn **arr = ready.vec;
expr_t *vec = vec_av_set.address ();
for (i = 0, n = ready.n_ready; i < n; i++)
if (EXPR_INSN_RTX (vec[i]) != arr[i])
{
- expr_t tmp;
-
for (j = i; j < n; j++)
if (EXPR_INSN_RTX (vec[j]) == arr[i])
break;
gcc_assert (j < n);
- tmp = vec[i];
- vec[i] = vec[j];
- vec[j] = tmp;
+ std::swap (vec[i], vec[j]);
}
}
number is ISSUE_MORE. FENCE and BEST_INSN are the current fence
and the insn chosen for scheduling, respectively. */
static int
-invoke_aftermath_hooks (fence_t fence, rtx best_insn, int issue_more)
+invoke_aftermath_hooks (fence_t fence, rtx_insn *best_insn, int issue_more)
{
gcc_assert (INSN_P (best_insn));
/* Estimate the cost of issuing INSN on DFA state STATE. */
static int
-estimate_insn_cost (rtx insn, state_t state)
+estimate_insn_cost (rtx_insn *insn, state_t state)
{
static state_t temp = NULL;
int cost;
static int
get_expr_cost (expr_t expr, fence_t fence)
{
- rtx insn = EXPR_INSN_RTX (expr);
+ rtx_insn *insn = EXPR_INSN_RTX (expr);
if (recog_memoized (insn) < 0)
{
/* Move note_list from the upper bb. */
gcc_assert (BB_NOTE_LIST (new_bb) == NULL_RTX);
- SET_BB_NOTE_LIST (new_bb) = BB_NOTE_LIST (bb);
- SET_BB_NOTE_LIST (bb) = NULL_RTX;
+ BB_NOTE_LIST (new_bb) = BB_NOTE_LIST (bb);
+ BB_NOTE_LIST (bb) = NULL;
gcc_assert (e2->dest == bb);
{
sel_global_bb_info_def gbi;
sel_region_bb_info_def rbi;
- int i;
if (sched_verbose >= 2)
sel_print ("Swapping block ids %i and %i\n",
new_bb->index, succ->index);
- i = new_bb->index;
- new_bb->index = succ->index;
- succ->index = i;
+ std::swap (new_bb->index, succ->index);
SET_BASIC_BLOCK_FOR_FN (cfun, new_bb->index, new_bb);
SET_BASIC_BLOCK_FOR_FN (cfun, succ->index, succ);
sizeof (rbi));
memcpy (SEL_REGION_BB_INFO (succ), &rbi, sizeof (rbi));
- i = BLOCK_TO_BB (new_bb->index);
- BLOCK_TO_BB (new_bb->index) = BLOCK_TO_BB (succ->index);
- BLOCK_TO_BB (succ->index) = i;
+ std::swap (BLOCK_TO_BB (new_bb->index),
+ BLOCK_TO_BB (succ->index));
- i = CONTAINING_RGN (new_bb->index);
- CONTAINING_RGN (new_bb->index) = CONTAINING_RGN (succ->index);
- CONTAINING_RGN (succ->index) = i;
+ std::swap (CONTAINING_RGN (new_bb->index),
+ CONTAINING_RGN (succ->index));
- for (i = 0; i < current_nr_blocks; i++)
+ for (int i = 0; i < current_nr_blocks; i++)
if (BB_TO_BLOCK (i) == succ->index)
BB_TO_BLOCK (i) = new_bb->index;
else if (BB_TO_BLOCK (i) == new_bb->index)
CODE_LABEL_NUMBER (BB_HEAD (new_bb)),
CODE_LABEL_NUMBER (BB_HEAD (succ)));
- i = CODE_LABEL_NUMBER (BB_HEAD (new_bb));
- CODE_LABEL_NUMBER (BB_HEAD (new_bb))
- = CODE_LABEL_NUMBER (BB_HEAD (succ));
- CODE_LABEL_NUMBER (BB_HEAD (succ)) = i;
+ std::swap (CODE_LABEL_NUMBER (BB_HEAD (new_bb)),
+ CODE_LABEL_NUMBER (BB_HEAD (succ)));
}
}
}
removed already. */
if (DEBUG_INSN_P (place_to_insert))
{
- rtx insn = sel_bb_head (book_block);
+ rtx_insn *insn = sel_bb_head (book_block);
while (insn != place_to_insert &&
(DEBUG_INSN_P (insn) || NOTE_P (insn)))
find_seqno_for_bookkeeping (insn_t place_to_insert, insn_t join_point)
{
int seqno;
- rtx next;
/* Check if we are about to insert bookkeeping copy before a jump, and use
jump's seqno for the copy; otherwise, use JOIN_POINT's seqno. */
- next = NEXT_INSN (place_to_insert);
+ rtx_insn *next = NEXT_INSN (place_to_insert);
if (INSN_P (next)
&& JUMP_P (next)
&& BLOCK_FOR_INSN (next) == BLOCK_FOR_INSN (place_to_insert))
static insn_t
emit_bookkeeping_insn (insn_t place_to_insert, expr_t c_expr, int new_seqno)
{
- rtx new_insn_rtx = create_copy_of_insn_rtx (EXPR_INSN_RTX (c_expr));
+ rtx_insn *new_insn_rtx = create_copy_of_insn_rtx (EXPR_INSN_RTX (c_expr));
vinsn_t new_vinsn
= create_vinsn_from_insn_rtx (new_insn_rtx,
...
*/
static void
-move_cond_jump (rtx insn, bnd_t bnd)
+move_cond_jump (rtx_insn *insn, bnd_t bnd)
{
edge ft_edge;
basic_block block_from, block_next, block_new, block_bnd, bb;
- rtx next, prev, link, head;
+ rtx_insn *next, *prev, *link, *head;
block_from = BLOCK_FOR_INSN (insn);
block_bnd = BLOCK_FOR_INSN (BND_TO (bnd));
/* Jump is moved to the boundary. */
next = PREV_INSN (insn);
- SET_BND_TO (bnd) = insn;
+ BND_TO (bnd) = insn;
ft_edge = find_fallthru_edge_from (block_from);
block_next = ft_edge->dest;
head = BB_HEAD (block_new);
while (bb != block_from->next_bb)
{
- rtx from, to;
+ rtx_insn *from, *to;
from = bb == block_bnd ? prev : sel_bb_head (bb);
to = bb == block_from ? next : sel_bb_end (bb);
{
gcc_assert (FENCE_INSN (fence) == BND_TO (bnd));
FENCE_INSN (fence) = bnd_to;
- SET_BND_TO (bnd) = bnd_to;
+ BND_TO (bnd) = bnd_to;
}
av_set_clear (&BND_AV (bnd));
static void ATTRIBUTE_UNUSED
move_nop_to_previous_block (insn_t nop, basic_block prev_bb)
{
- insn_t prev_insn, next_insn, note;
+ insn_t prev_insn, next_insn;
gcc_assert (sel_bb_head_p (nop)
&& prev_bb == BLOCK_FOR_INSN (nop)->prev_bb);
- note = bb_note (BLOCK_FOR_INSN (nop));
+ rtx_note *note = bb_note (BLOCK_FOR_INSN (nop));
prev_insn = sel_bb_end (prev_bb);
next_insn = NEXT_INSN (nop);
gcc_assert (prev_insn != NULL_RTX
SET_NEXT_INSN (nop) = note;
SET_PREV_INSN (next_insn) = note;
- SET_BB_END (prev_bb) = nop;
+ BB_END (prev_bb) = nop;
BLOCK_FOR_INSN (nop) = prev_bb;
}
SCHED_GROUP_P (insn) = 0;
}
else
- FENCE_SCHED_NEXT (fence) = NULL_RTX;
+ FENCE_SCHED_NEXT (fence) = NULL;
if (INSN_UID (insn) < FENCE_READY_TICKS_SIZE (fence))
FENCE_READY_TICKS (fence) [INSN_UID (insn)] = 0;
av_set_iterator i;
av_set_t old_av_set = NULL;
expr_t cur_expr;
- rtx bb_end = sel_bb_end (book_block);
+ rtx_insn *bb_end = sel_bb_end (book_block);
/* First, get correct liveness in the bookkeeping block. The problem is
the range between the bookeeping insn and the end of block. */
/* Track bookkeeping copies created, insns scheduled, and blocks for
rescheduling when INSN is found by move_op. */
static void
-track_scheduled_insns_and_blocks (rtx insn)
+track_scheduled_insns_and_blocks (rtx_insn *insn)
{
/* Even if this insn can be a copy that will be removed during current move_op,
we still need to count it as an originator. */
/* Emit a register-register copy for INSN if needed. Return true if
emitted one. PARAMS is the move_op static parameters. */
static bool
-maybe_emit_renaming_copy (rtx insn,
+maybe_emit_renaming_copy (rtx_insn *insn,
moveop_static_params_p params)
{
bool insn_emitted = false;
Return true if we've emitted one. PARAMS is the move_op static
parameters. */
static bool
-maybe_emit_speculative_check (rtx insn, expr_t expr,
+maybe_emit_speculative_check (rtx_insn *insn, expr_t expr,
moveop_static_params_p params)
{
bool insn_emitted = false;
insn such as renaming/speculation. Return true if one of such
transformations actually happened, and we have emitted this insn. */
static bool
-handle_emitting_transformations (rtx insn, expr_t expr,
+handle_emitting_transformations (rtx_insn *insn, expr_t expr,
moveop_static_params_p params)
{
bool insn_emitted = false;
leave a NOP there till the return to fill_insns. */
static bool
-need_nop_to_preserve_insn_bb (rtx insn)
+need_nop_to_preserve_insn_bb (rtx_insn *insn)
{
insn_t bb_head, bb_end, bb_next, in_next;
basic_block bb = BLOCK_FOR_INSN (insn);
/* Remove INSN from stream. When ONLY_DISCONNECT is true, its data
is not removed but reused when INSN is re-emitted. */
static void
-remove_insn_from_stream (rtx insn, bool only_disconnect)
+remove_insn_from_stream (rtx_insn *insn, bool only_disconnect)
{
/* If there's only one insn in the BB, make sure that a nop is
inserted into it, so the basic block won't disappear when we'll
{
int res = 0;
succ_iterator succ_i;
- rtx succ;
+ insn_t succ;
basic_block bb;
int old_index;
unsigned old_succs;
if (!expr)
{
int res;
- rtx last_insn = PREV_INSN (insn);
+ rtx_insn *last_insn = PREV_INSN (insn);
bool added_to_path;
gcc_assert (insn == sel_bb_end (bb));
init_seqno_1 (basic_block bb, sbitmap visited_bbs, bitmap blocks_to_reschedule)
{
int bbi = BLOCK_TO_BB (bb->index);
- insn_t insn, note = bb_note (bb);
+ insn_t insn;
insn_t succ_insn;
succ_iterator si;
+ rtx_note *note = bb_note (bb);
bitmap_set_bit (visited_bbs, bbi);
if (blocks_to_reschedule)
bitmap_clear_bit (blocks_to_reschedule, bb->index);
for (i = 0; i < current_nr_blocks; i++)
{
basic_block bb = BASIC_BLOCK_FOR_FN (cfun, BB_TO_BLOCK (i));
- rtx insn;
+ rtx_insn *insn;
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))