/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
/* Record one modification to rtl structure
to be undone by storing old_contents into *where. */
+enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE };
+
struct undo
{
struct undo *next;
- enum { UNDO_RTX, UNDO_INT, UNDO_MODE } kind;
+ enum undo_kind kind;
union { rtx r; int i; enum machine_mode m; } old_contents;
union { rtx *r; int *i; } where;
};
static rtx *
find_single_use (rtx dest, rtx insn, rtx *ploc)
{
+ basic_block bb;
rtx next;
rtx *result;
rtx link;
if (!REG_P (dest))
return 0;
- for (next = next_nonnote_insn (insn);
- next != 0 && !LABEL_P (next);
- next = next_nonnote_insn (next))
+ bb = BLOCK_FOR_INSN (insn);
+ for (next = NEXT_INSN (insn);
+ next && BLOCK_FOR_INSN (next) == bb;
+ next = NEXT_INSN (next))
if (INSN_P (next) && dead_or_set_p (next, dest))
{
for (link = LOG_LINKS (next); link; link = XEXP (link, 1))
Also set any known values so that we can use it while searching
for what bits are known to be set. */
- label_tick = label_tick_ebb_start = 1;
-
setup_incoming_promotions (first);
create_log_links ();
+ label_tick_ebb_start = ENTRY_BLOCK_PTR->index;
FOR_EACH_BB (this_basic_block)
{
optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
- label_tick++;
+ label_tick = this_basic_block->index;
+ if (!single_pred_p (this_basic_block)
+ || single_pred (this_basic_block)->index != label_tick - 1)
+ label_tick_ebb_start = label_tick;
FOR_BB_INSNS (this_basic_block, insn)
if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
{
fprintf(dump_file, "insn_cost %d: %d\n",
INSN_UID (insn), INSN_COST (insn));
}
- else if (LABEL_P (insn))
- label_tick_ebb_start = label_tick;
}
nonzero_sign_valid = 1;
/* Now scan all the insns in forward order. */
- label_tick = label_tick_ebb_start = 1;
+ label_tick_ebb_start = ENTRY_BLOCK_PTR->index;
init_reg_last ();
setup_incoming_promotions (first);
FOR_EACH_BB (this_basic_block)
{
+ optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
- label_tick++;
+ label_tick = this_basic_block->index;
+ if (!single_pred_p (this_basic_block)
+ || single_pred (this_basic_block)->index != label_tick - 1)
+ label_tick_ebb_start = label_tick;
rtl_profile_for_bb (this_basic_block);
for (insn = BB_HEAD (this_basic_block);
insn != NEXT_INSN (BB_END (this_basic_block));
retry:
;
}
- else if (LABEL_P (insn))
- label_tick_ebb_start = label_tick;
}
}
}
+/* Delete the conditional jump INSN and adjust the CFG correspondingly.
+ Note that the INSN should be deleted *after* removing dead edges, so
+ that the kept edge is the fallthrough edge for a (set (pc) (pc))
+ but not for a (set (pc) (label_ref FOO)). */
+
+static void
+update_cfg_for_uncondjump (rtx insn)
+{
+ basic_block bb = BLOCK_FOR_INSN (insn);
+
+ if (BB_END (bb) == insn)
+ purge_dead_edges (bb);
+
+ delete_insn (insn);
+ if (EDGE_COUNT (bb->succs) == 1)
+ single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
+}
+
+
/* Try to combine the insns I1 and I2 into I3.
Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
/* Notes that I1, I2 or I3 is a MULT operation. */
int have_mult = 0;
int swap_i2i3 = 0;
+ int changed_i3_dest = 0;
int maxreg;
rtx temp;
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
if (insn_code_number >= 0)
- {
- /* If we will be able to accept this, we have made a
- change to the destination of I3. This requires us to
- do a few adjustments. */
-
- PATTERN (i3) = newpat;
- adjust_for_new_dest (i3);
- }
+ changed_i3_dest = 1;
}
}
return 0;
}
+ /* If we will be able to accept this, we have made a
+ change to the destination of I3. This requires us to
+ do a few adjustments. */
+
+ if (changed_i3_dest)
+ {
+ PATTERN (i3) = newpat;
+ adjust_for_new_dest (i3);
+ }
+
/* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
if (i3dest_killed)
{
if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
- NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i3dest_killed,
+ NULL_RTX),
NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
else
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
- NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i3dest_killed,
+ NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
elim_i2, elim_i1);
}
if (i2dest_in_i2src)
{
if (newi2pat && reg_set_p (i2dest, newi2pat))
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
if (i1dest_in_i1src)
{
if (newi2pat && reg_set_p (i1dest, newi2pat))
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
- distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
+ distribute_notes (alloc_reg_note (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
-
- /* Set new_direct_jump_p if a new return or simple jump instruction
- has been created.
-
- If I3 is now an unconditional jump, ensure that it has a
- BARRIER following it since it may have initially been a
- conditional jump. It may also be the last nonnote insn. */
-
- if (returnjump_p (i3) || any_uncondjump_p (i3))
- {
- *new_direct_jump_p = 1;
- mark_jump_label (PATTERN (i3), i3, 0);
-
- if ((temp = next_nonnote_insn (i3)) == NULL_RTX
- || !BARRIER_P (temp))
- emit_barrier_after (i3);
- }
-
- if (undobuf.other_insn != NULL_RTX
- && (returnjump_p (undobuf.other_insn)
- || any_uncondjump_p (undobuf.other_insn)))
- {
- *new_direct_jump_p = 1;
-
- if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX
- || !BARRIER_P (temp))
- emit_barrier_after (undobuf.other_insn);
- }
-
- /* An NOOP jump does not need barrier, but it does need cleaning up
- of CFG. */
- if (GET_CODE (newpat) == SET
- && SET_SRC (newpat) == pc_rtx
- && SET_DEST (newpat) == pc_rtx)
- *new_direct_jump_p = 1;
}
-
+
if (undobuf.other_insn != NULL_RTX)
{
if (dump_file)
df_insn_rescan (i3);
}
+ /* Set new_direct_jump_p if a new return or simple jump instruction
+ has been created. Adjust the CFG accordingly. */
+
+ if (returnjump_p (i3) || any_uncondjump_p (i3))
+ {
+ *new_direct_jump_p = 1;
+ mark_jump_label (PATTERN (i3), i3, 0);
+ update_cfg_for_uncondjump (i3);
+ }
+
+ if (undobuf.other_insn != NULL_RTX
+ && (returnjump_p (undobuf.other_insn)
+ || any_uncondjump_p (undobuf.other_insn)))
+ {
+ *new_direct_jump_p = 1;
+ update_cfg_for_uncondjump (undobuf.other_insn);
+ }
+
+ /* A noop might also need cleaning up of CFG, if it comes from the
+ simplification of a jump. */
+ if (GET_CODE (newpat) == SET
+ && SET_SRC (newpat) == pc_rtx
+ && SET_DEST (newpat) == pc_rtx)
+ {
+ *new_direct_jump_p = 1;
+ update_cfg_for_uncondjump (i3);
+ }
+
combine_successes++;
undo_commit ();
return gen_lowpart (mode, XEXP (x, 0));
break;
-#ifdef HAVE_cc0
- case COMPARE:
- /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
- using cc0, in which case we want to leave it as a COMPARE
- so we can distinguish it from a register-register-copy. */
- if (XEXP (x, 1) == const0_rtx)
- return XEXP (x, 0);
-
- /* x - 0 is the same as x unless x's mode has signed zeros and
- allows rounding towards -infinity. Under those conditions,
- 0 - 0 is -0. */
- if (!(HONOR_SIGNED_ZEROS (GET_MODE (XEXP (x, 0)))
- && HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (XEXP (x, 0))))
- && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
- return XEXP (x, 0);
- break;
-#endif
-
case CONST:
/* (const (const X)) can become (const X). Do it this way rather than
returning the inner CONST since CONST can be shared with a
{
int other_changed_previously = other_changed;
unsigned HOST_WIDE_INT mask;
+ rtx old_cc_use = *cc_use;
SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
dest, const0_rtx));
if ((recog_for_combine (&pat, other_insn, ¬e) < 0
&& ! check_asm_operands (pat)))
{
- PUT_CODE (*cc_use, old_code);
+ *cc_use = old_cc_use;
other_changed = 0;
op0 = simplify_gen_binary (XOR, GET_MODE (op0),
if (other_changed)
undobuf.other_insn = other_insn;
-#ifdef HAVE_cc0
- /* If we are now comparing against zero, change our source if
- needed. If we do not use cc0, we always have a COMPARE. */
- if (op1 == const0_rtx && dest == cc0_rtx)
- {
- SUBST (SET_SRC (x), op0);
- src = op0;
- }
- else
-#endif
-
/* Otherwise, if we didn't previously have a COMPARE in the
correct mode, we need one. */
if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode)
zero_extend to avoid the reload that would otherwise be required. */
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
+ && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (src)))
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != UNKNOWN
&& SUBREG_BYTE (src) == 0
&& (GET_MODE_SIZE (GET_MODE (src))
if (GET_CODE (rhs) == CONST_INT
&& GET_CODE (lhs) == ASHIFT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
- && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1)))
+ && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1))
+ && INTVAL (rhs) < mode_width)
{
new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
new_rtx = make_extraction (mode, new_rtx,
&& (OBJECT_P (SUBREG_REG (lhs))))
&& GET_CODE (rhs) == CONST_INT
&& INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
+ && INTVAL (rhs) < mode_width
&& (new_rtx = extract_left_shift (lhs, INTVAL (rhs))) != 0)
new_rtx = make_extraction (mode, make_compound_operation (new_rtx, next_code),
0, NULL_RTX, mode_width - INTVAL (rhs),
&& (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
return gen_lowpart (mode, x);
+ /* The arithmetic simplifications here do the wrong thing on vector modes. */
+ if (VECTOR_MODE_P (mode) || VECTOR_MODE_P (GET_MODE (x)))
+ return gen_lowpart (mode, x);
+
switch (code)
{
case CLOBBER:
&& op0 == AND)
op0 = UNKNOWN;
+ *pop0 = op0;
+
/* ??? Slightly redundant with the above mask, but not entirely.
Moving this above means we'd have to sign-extend the mode mask
for the final test. */
- const0 = trunc_int_for_mode (const0, mode);
-
- *pop0 = op0;
- *pconst0 = const0;
+ if (op0 != UNKNOWN && op0 != NEG)
+ *pconst0 = trunc_int_for_mode (const0, mode);
return 1;
}
if (GET_CODE (varop) == CLOBBER)
return NULL_RTX;
- /* If we discovered we had to complement VAROP, leave. Making a NOT
- here would cause an infinite loop. */
- if (complement_p)
- break;
-
/* Convert ROTATERT to ROTATE. */
if (code == ROTATERT)
{
}
}
+ /* If we discovered we had to complement VAROP, leave. Making a NOT
+ here would cause an infinite loop. */
+ if (complement_p)
+ break;
+
/* An arithmetic right shift of a quantity known to be -1 or 0
is a no-op. */
if (code == ASHIFTRT
if (outer_op != UNKNOWN)
{
- if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
+ if (GET_RTX_CLASS (outer_op) != RTX_UNARY
+ && GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
outer_const = trunc_int_for_mode (outer_const, result_mode);
if (outer_op == AND)
if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH)
{
gcc_assert (REG_P (XEXP (XVECEXP (newpat, 0, i), 0)));
- notes = gen_rtx_EXPR_LIST (REG_UNUSED,
- XEXP (XVECEXP (newpat, 0, i), 0), notes);
+ notes = alloc_reg_note (REG_UNUSED,
+ XEXP (XVECEXP (newpat, 0, i), 0), notes);
}
}
pat = newpat;
}
fail:
- return gen_rtx_CLOBBER (imode, const0_rtx);
+ return gen_rtx_CLOBBER (omode, const0_rtx);
}
\f
/* Simplify a comparison between *POP0 and *POP1 where CODE is the
&& ((unsigned HOST_WIDE_INT) const_op
< (((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1))))
- && optab_handler (cmp_optab, mode)->insn_code != CODE_FOR_nothing)
+ && have_insn_for (COMPARE, mode))
{
op0 = XEXP (op0, 0);
continue;
&& (unsigned_comparison_p || equality_comparison_p)
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
- && optab_handler (cmp_optab, mode)->insn_code != CODE_FOR_nothing)
+ && have_insn_for (COMPARE, mode))
{
op0 = XEXP (op0, 0);
continue;
rsp->last_set = insn;
rsp->last_set_value = 0;
- rsp->last_set_mode = 0;
+ rsp->last_set_mode = VOIDmode;
rsp->last_set_nonzero_bits = 0;
rsp->last_set_sign_bit_copies = 0;
rsp->last_death = 0;
- rsp->truncated_to_mode = 0;
+ rsp->truncated_to_mode = VOIDmode;
}
/* Mark registers that are being referenced in this value. */
rsp->last_set_invalid = 1;
rsp->last_set = insn;
rsp->last_set_value = 0;
- rsp->last_set_mode = 0;
+ rsp->last_set_mode = VOIDmode;
rsp->last_set_nonzero_bits = 0;
rsp->last_set_sign_bit_copies = 0;
rsp->last_death = 0;
- rsp->truncated_to_mode = 0;
+ rsp->truncated_to_mode = VOIDmode;
}
last_call_luid = mem_last_set = DF_INSN_LUID (insn);
return 0;
}
- /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or
- beginning of function. */
- for (; insn && !LABEL_P (insn) && !BARRIER_P (insn);
- insn = prev_nonnote_insn (insn))
+ /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, or
+ beginning of basic block. */
+ block = BLOCK_FOR_INSN (insn);
+ for (;;)
{
- note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
- if (reg_dead_flag)
- return reg_dead_flag == 1 ? 1 : 0;
+ if (INSN_P (insn))
+ {
+ note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
+ if (reg_dead_flag)
+ return reg_dead_flag == 1 ? 1 : 0;
- if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
- return 1;
- }
+ if (find_regno_note (insn, REG_DEAD, reg_dead_regno))
+ return 1;
+ }
- /* Get the basic block that we were in. */
- if (insn == 0)
- block = ENTRY_BLOCK_PTR->next_bb;
- else
- {
- FOR_EACH_BB (block)
- if (insn == BB_HEAD (block))
- break;
+ if (insn == BB_HEAD (block))
+ break;
- if (block == EXIT_BLOCK_PTR)
- return 0;
+ insn = PREV_INSN (insn);
}
+ /* Look at live-in sets for the basic block that we were in. */
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
if (REGNO_REG_SET_P (df_get_live_in (block), i))
return 0;
return;
if (where_dead
+ && BLOCK_FOR_INSN (where_dead) == BLOCK_FOR_INSN (to_insn)
&& DF_INSN_LUID (where_dead) >= from_luid
&& DF_INSN_LUID (where_dead) < DF_INSN_LUID (to_insn))
{
*pnotes = note;
}
else
- *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
+ *pnotes = alloc_reg_note (REG_DEAD, x, *pnotes);
}
return;
distribute_links (LOG_LINKS (tem));
SET_INSN_DELETED (tem);
+ if (tem == i2)
+ i2 = NULL_RTX;
#ifdef HAVE_cc0
/* Delete the setter too. */
distribute_links (LOG_LINKS (cc0_setter));
SET_INSN_DELETED (cc0_setter);
+ if (cc0_setter == i2)
+ i2 = NULL_RTX;
}
#endif
}
&& ! reg_bitfield_target_p (piece,
PATTERN (place)))
{
- rtx new_note
- = gen_rtx_EXPR_LIST (REG_DEAD, piece, NULL_RTX);
+ rtx new_note = alloc_reg_note (REG_DEAD, piece,
+ NULL_RTX);
distribute_notes (new_note, place, place,
NULL_RTX, NULL_RTX, NULL_RTX);
}
if (place2)
- REG_NOTES (place2)
- = gen_rtx_fmt_ee (GET_CODE (note), REG_NOTE_KIND (note),
- XEXP (note, 0), REG_NOTES (place2));
+ add_reg_note (place2, REG_NOTE_KIND (note), XEXP (note, 0));
}
}
\f
NULL, /* next */
0, /* static_pass_number */
TV_COMBINE, /* tv_id */
- 0, /* properties_required */
+ PROP_cfglayout, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_ggc_collect, /* todo_flags_finish */
}
};
-