/* Instruction scheduling pass. Selective scheduler and pipeliner.
- Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GCC.
/* Set of hooks for performing move_op and find_used_regs routines with
code_motion_path_driver. */
-struct code_motion_path_driver_info_def move_op_hooks, fur_hooks;
+extern struct code_motion_path_driver_info_def move_op_hooks, fur_hooks;
/* True if/when we want to emulate Haifa scheduler in the common code.
This is used in sched_rgn_local_init and in various places in
static basic_block generate_bookkeeping_insn (expr_t, edge, edge);
static bool find_used_regs (insn_t, av_set_t, regset, struct reg_rename *,
def_list_t *);
-static bool move_op (insn_t, av_set_t, expr_t, rtx, expr_t);
-static bool code_motion_path_driver (insn_t, av_set_t, ilist_t,
- cmpd_local_params_p, void *);
+static bool move_op (insn_t, av_set_t, expr_t, rtx, expr_t, bool*);
+static int code_motion_path_driver (insn_t, av_set_t, ilist_t,
+ cmpd_local_params_p, void *);
static void sel_sched_region_1 (void);
static void sel_sched_region_2 (int);
static av_set_t compute_av_set_inside_bb (insn_t, ilist_t, int, bool);
{
/* Bail out if we occupy more than one register. */
if (REG_P (*cur_rtx)
+ && HARD_REGISTER_P (*cur_rtx)
&& hard_regno_nregs[REGNO(*cur_rtx)][GET_MODE (*cur_rtx)] > 1)
{
p->n = 0;
/* 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, int to)
+sel_hard_regno_rename_ok (int from ATTRIBUTE_UNUSED, int to ATTRIBUTE_UNUSED)
{
#ifdef HARD_REGNO_RENAME_OK
/* Check whether this is all calculated. */
init_hard_regs_data (void)
{
int cur_reg = 0;
- enum machine_mode cur_mode = 0;
+ int cur_mode = 0;
CLEAR_HARD_REG_SET (sel_hrd.regs_ever_used);
for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++)
/* Create a recovery block if target is going to emit branchy check, or if
ORIG_INSN was speculative already. */
- if (targetm.sched.needs_block_p (EXPR_INSN_RTX (c_expr))
+ if (targetm.sched.needs_block_p (check_ds)
|| EXPR_SPEC_DONE_DS (INSN_EXPR (orig_insn)) != 0)
{
recovery_block = sel_create_recovery_block (orig_insn);
if (INSN_NOP_P (insn))
return;
- df_simulate_one_insn (BLOCK_FOR_INSN (insn), insn, lv);
+ df_simulate_one_insn_backwards (BLOCK_FOR_INSN (insn), insn, lv);
}
/* Return livness set at the end of BB. */
if (INSN_P (next)
&& JUMP_P (next)
&& BLOCK_FOR_INSN (next) == BLOCK_FOR_INSN (place_to_insert))
- seqno = INSN_SEQNO (next);
+ {
+ gcc_assert (INSN_SCHED_TIMES (next) == 0);
+ seqno = INSN_SEQNO (next);
+ }
else if (INSN_SEQNO (join_point) > 0)
seqno = INSN_SEQNO (join_point);
else
- seqno = get_seqno_by_preds (place_to_insert);
+ {
+ seqno = get_seqno_by_preds (place_to_insert);
+
+ /* Sometimes the fences can move in such a way that there will be
+ no instructions with positive seqno around this bookkeeping.
+ This means that there will be no way to get to it by a regular
+ fence movement. Never mind because we pick up such pieces for
+ rescheduling anyways, so any positive value will do for now. */
+ if (seqno < 0)
+ {
+ gcc_assert (pipelining_p);
+ seqno = 1;
+ }
+ }
gcc_assert (seqno > 0);
return seqno;
/* Find original instructions for EXPR_SEQ and move it to BND boundary.
Return the expression to emit in C_EXPR. */
-static void
+static bool
move_exprs_to_boundary (bnd_t bnd, expr_t expr_vliw,
av_set_t expr_seq, expr_t c_expr)
{
- bool b;
+ bool b, should_move;
unsigned book_uid;
bitmap_iterator bi;
int n_bookkeeping_copies_before_moveop;
bitmap_clear (current_originators);
b = move_op (BND_TO (bnd), expr_seq, expr_vliw,
- get_dest_from_orig_ops (expr_seq), c_expr);
+ get_dest_from_orig_ops (expr_seq), c_expr, &should_move);
/* We should be able to find the expression we've chosen for
scheduling. */
- gcc_assert (b == 1);
+ gcc_assert (b);
if (stat_bookkeeping_copies > n_bookkeeping_copies_before_moveop)
stat_insns_needed_bookkeeping++;
bitmap_copy (INSN_ORIGINATORS_BY_UID (book_uid),
current_originators);
}
+
+ return should_move;
}
expr_t c_expr = XALLOCA (expr_def);
insn_t place_to_insert;
insn_t insn;
- bool cant_move;
+ bool should_move;
expr_seq = find_sequential_best_exprs (bnd, expr_vliw, true);
move_cond_jump (insn, bnd);
}
- /* Calculate cant_move now as EXPR_WAS_RENAMED can change after move_op
- meaning that there was *any* renaming somewhere. */
- cant_move = EXPR_WAS_CHANGED (expr_vliw) || EXPR_WAS_RENAMED (expr_vliw);
-
/* Find a place for C_EXPR to schedule. */
place_to_insert = prepare_place_to_insert (bnd);
- move_exprs_to_boundary (bnd, expr_vliw, expr_seq, c_expr);
+ should_move = move_exprs_to_boundary (bnd, expr_vliw, expr_seq, c_expr);
clear_expr (c_expr);
/* Add the instruction. The corner case to care about is when
vinsn_new = vinsn_copy (EXPR_VINSN (expr_vliw), false);
change_vinsn_in_expr (expr_vliw, vinsn_new);
- cant_move = 1;
+ should_move = false;
}
- if (cant_move)
+ if (should_move)
+ insn = sel_move_insn (expr_vliw, seqno, place_to_insert);
+ else
insn = emit_insn_from_expr_after (expr_vliw, NULL, seqno,
place_to_insert);
- else
- insn = sel_move_insn (expr_vliw, seqno, place_to_insert);
/* Return the nops generated for preserving of data sets back
into pool. */
insn_emitted = handle_emitting_transformations (insn, expr, params);
only_disconnect = (params->uid == INSN_UID (insn)
&& ! insn_emitted && ! EXPR_WAS_CHANGED (expr));
+
+ /* Mark that we've disconnected an insn. */
+ if (only_disconnect)
+ params->uid = -1;
remove_insn_from_stream (insn, only_disconnect);
}
#endif
/* Merge data, clean up, etc. */
- if (code_motion_path_driver_info->after_merge_succs)
+ if (res != -1 && code_motion_path_driver_info->after_merge_succs)
code_motion_path_driver_info->after_merge_succs (&lparams, static_params);
return res;
Returns whether original instructions were found. Note that top-level
code_motion_path_driver always returns true. */
-static bool
+static int
code_motion_path_driver (insn_t insn, av_set_t orig_ops, ilist_t path,
cmpd_local_params_p local_params_in,
void *static_params)
DEST is the register chosen for scheduling the current expr. Insert
bookkeeping code in the join points. EXPR_VLIW is the chosen expression,
C_EXPR is how it looks like at the given cfg point.
+ Set *SHOULD_MOVE to indicate whether we have only disconnected
+ one of the insns found.
Returns whether original instructions were found, which is asserted
to be true in the caller. */
static bool
move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw,
- rtx dest, expr_t c_expr)
+ rtx dest, expr_t c_expr, bool *should_move)
{
struct moveop_static_params sparams;
struct cmpd_local_params lparams;
if (sparams.was_renamed)
EXPR_WAS_RENAMED (expr_vliw) = true;
+ *should_move = (sparams.uid == -1);
+
return res;
}
\f
static void
purge_empty_blocks (void)
{
- int i ;
+ /* Do not attempt to delete preheader. */
+ int i = sel_is_loop_preheader_p (BASIC_BLOCK (BB_TO_BLOCK (0))) ? 1 : 0;
- for (i = 1; i < current_nr_blocks; )
+ while (i < current_nr_blocks)
{
basic_block b = BASIC_BLOCK (BB_TO_BLOCK (i));