/* RTL-level loop invariant motion.
- Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GCC.
<http://www.gnu.org/licenses/>. */
/* This implements the loop invariant motion pass. It is very simple
- (no calls, libcalls, etc.). This should be sufficient to cleanup things
- like address arithmetics -- other more complicated invariants should be
- eliminated on tree level either in tree-ssa-loop-im.c or in tree-ssa-pre.c.
+ (no calls, no loads/stores, etc.). This should be sufficient to cleanup
+ things like address arithmetics -- other more complicated invariants should
+ be eliminated on GIMPLE either in tree-ssa-loop-im.c or in tree-ssa-pre.c.
We proceed loop by loop -- it is simpler than trying to handle things
globally and should not lose much. First we inspect all sets inside loop
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
/* Just handle the most trivial case where we load from an unchanging
location (most importantly, pic tables). */
- if (MEM_READONLY_P (x))
+ if (MEM_READONLY_P (x) && !MEM_VOLATILE_P (x))
break;
return false;
{
struct df_link *defs;
struct df_ref *def;
- basic_block bb = BLOCK_FOR_INSN (use->insn), def_bb;
+ basic_block bb = DF_REF_BB (use), def_bb;
if (use->flags & DF_REF_READ_WRITE)
return NULL;
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
FOR_BB_INSNS (body[i], insn)
{
if (CALL_P (insn)
- && !CONST_OR_PURE_CALL_P (insn))
+ && (RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)
+ || !RTL_CONST_OR_PURE_CALL_P (insn)))
{
has_call = true;
bitmap_set_bit (may_exit, i);
if (dump_file)
{
+ df_dump_region (dump_file);
fprintf (dump_file, "*****starting processing of loop ******\n");
print_rtl_with_bb (dump_file, get_insns ());
fprintf (dump_file, "*****ending processing of loop ******\n");
static bool
check_dependencies (rtx insn, bitmap depends_on)
{
+ struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
struct df_ref **use_rec;
basic_block bb = BLOCK_FOR_INSN (insn);
- for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+ for (use_rec = DF_INSN_INFO_USES (insn_info); *use_rec; use_rec++)
if (!check_dependency (bb, *use_rec, depends_on))
return false;
- for (use_rec = DF_INSN_EQ_USES (insn); *use_rec; use_rec++)
+ for (use_rec = DF_INSN_INFO_EQ_USES (insn_info); *use_rec; use_rec++)
if (!check_dependency (bb, *use_rec, depends_on))
return false;
bool simple = true;
struct invariant *inv;
- /* Until we get rid of LIBCALLS. */
- if (find_reg_note (insn, REG_RETVAL, NULL_RTX)
- || find_reg_note (insn, REG_LIBCALL, NULL_RTX)
- || find_reg_note (insn, REG_NO_CONFLICT, NULL_RTX))
- return;
-
#ifdef HAVE_cc0
/* We can't move a CC0 setter without the user. */
if (sets_cc0_p (insn))
static void
record_uses (rtx insn)
{
+ struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
struct df_ref **use_rec;
struct invariant *inv;
- for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+ for (use_rec = DF_INSN_INFO_USES (insn_info); *use_rec; use_rec++)
{
struct df_ref *use = *use_rec;
inv = invariant_for_use (use);
if (inv)
record_use (inv->def, DF_REF_REAL_LOC (use), DF_REF_INSN (use));
}
- for (use_rec = DF_INSN_EQ_USES (insn); *use_rec; use_rec++)
+ for (use_rec = DF_INSN_INFO_EQ_USES (insn_info); *use_rec; use_rec++)
{
struct df_ref *use = *use_rec;
inv = invariant_for_use (use);
if (always_reached
&& CALL_P (insn)
- && !CONST_OR_PURE_CALL_P (insn))
+ && (RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)
+ || ! RTL_CONST_OR_PURE_CALL_P (insn)))
always_reached = false;
}
}
{
unsigned i, regs_used, regs_needed = 0, new_regs;
struct invariant *inv = NULL;
- unsigned int n_regs = DF_REG_SIZE ();
+ unsigned int n_regs = DF_REG_SIZE (df);
if (!VEC_length (invariant_p, invariants))
return;
}
}
-/* Returns true if all insns in SEQ are valid. */
-
-static bool
-seq_insns_valid_p (rtx seq)
-{
- rtx x;
-
- for (x = seq; x; x = NEXT_INSN (x))
- if (insn_invalid_p (x))
- return false;
-
- return true;
-}
-
/* Move invariant INVNO out of the LOOP. Returns true if this succeeds, false
otherwise. */
struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
unsigned i;
basic_block preheader = loop_preheader_edge (loop)->src;
- rtx reg, set, dest, seq, op;
+ rtx reg, set, dest, note;
struct use *use;
bitmap_iterator bi;
need to create a temporary register. */
set = single_set (inv->insn);
dest = SET_DEST (set);
- reg = gen_reg_rtx (GET_MODE (dest));
+ reg = gen_reg_rtx_and_attrs (dest);
- /* If the SET_DEST of the invariant insn is a pseudo, we can just move
- the insn out of the loop. Otherwise, we have to use gen_move_insn
- to let emit_move_insn produce a valid instruction stream. */
- if (REG_P (dest) && !HARD_REGISTER_P (dest))
- {
- rtx note;
-
- emit_insn_after (gen_move_insn (dest, reg), inv->insn);
- SET_DEST (set) = reg;
- df_insn_rescan (inv->insn);
- reorder_insns (inv->insn, inv->insn, BB_END (preheader));
-
- /* If there is a REG_EQUAL note on the insn we just moved, and
- insn is in a basic block that is not always executed, the note
- may no longer be valid after we move the insn.
- Note that uses in REG_EQUAL notes are taken into account in
- the computation of invariants. Hence it is safe to retain the
- note even if the note contains register references. */
- if (! inv->always_executed
- && (note = find_reg_note (inv->insn, REG_EQUAL, NULL_RTX)))
- remove_note (inv->insn, note);
- }
- else
- {
- start_sequence ();
- op = force_operand (SET_SRC (set), reg);
- if (!op)
- {
- end_sequence ();
- goto fail;
- }
- if (op != reg)
- emit_move_insn (reg, op);
- seq = get_insns ();
- end_sequence ();
-
- if (!seq_insns_valid_p (seq))
- goto fail;
- emit_insn_after (seq, BB_END (preheader));
-
- emit_insn_after (gen_move_insn (dest, reg), inv->insn);
- delete_insn (inv->insn);
- }
+ /* Try replacing the destination by a new pseudoregister. */
+ if (!validate_change (inv->insn, &SET_DEST (set), reg, false))
+ goto fail;
+ df_insn_rescan (inv->insn);
+
+ emit_insn_after (gen_move_insn (dest, reg), inv->insn);
+ reorder_insns (inv->insn, inv->insn, BB_END (preheader));
+
+ /* If there is a REG_EQUAL note on the insn we just moved, and
+ insn is in a basic block that is not always executed, the note
+ may no longer be valid after we move the insn.
+ Note that uses in REG_EQUAL notes are taken into account in
+ the computation of invariants. Hence it is safe to retain the
+ note even if the note contains register references. */
+ if (! inv->always_executed
+ && (note = find_reg_note (inv->insn, REG_EQUAL, NULL_RTX)))
+ remove_note (inv->insn, note);
}
else
{