/* Perform various loop optimizations, including strength reduction.
- Copyright (C) 1987, 88, 89, 91-99, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "flags.h"
#include "real.h"
#include "loop.h"
+#include "cselib.h"
#include "except.h"
#include "toplev.h"
/* Bound on pseudo register number before loop optimization.
A pseudo has valid regscan info if its number is < max_reg_before_loop. */
-int max_reg_before_loop;
+unsigned int max_reg_before_loop;
/* The value to pass to the next call of reg_scan_update. */
static int loop_max_reg;
of any registers used within the LIBCALL. */
int consec; /* Number of consecutive following insns
that must be moved with this one. */
- int regno; /* The register it sets */
+ unsigned int regno; /* The register it sets */
short lifetime; /* lifetime of that register;
may be adjusted when matching movables
that load the same value are found. */
static int replace_loop_mem PARAMS ((rtx *, void *));
static int replace_loop_reg PARAMS ((rtx *, void *));
static void note_reg_stored PARAMS ((rtx, rtx, void *));
-static void try_copy_prop PARAMS ((const struct loop *, rtx, int));
+static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
static int replace_label PARAMS ((rtx *, void *));
typedef struct rtx_and_int {
if (uid_luid[i] == 0)
uid_luid[i] = uid_luid[i - 1];
- /* If debugging and unrolling loops, we must replicate the tree
- nodes corresponding to the BLOCKs inside the loop, so that the
- original one to one mapping will remain. We sometimes unroll
- loops even when unroll_p is false, so we must always do this when
- debugging. */
- if (write_symbols != NO_DEBUG)
- find_loop_tree_blocks ();
-
/* Determine if the function has indirect jump. On some systems
this prevents low overhead loop instructions from being used. */
indirect_jump_in_function = indirect_jump_in_function_p (f);
scan_loop (loop, unroll_p, bct_p);
}
- /* Replicate the BLOCKs. */
+ /* If there were lexical blocks inside the loop, they have been
+ replicated. We will now have more than one NOTE_INSN_BLOCK_BEG
+ and NOTE_INSN_BLOCK_END for each such block. We must duplicate
+ the BLOCKs as well. */
if (write_symbols != NO_DEBUG)
- unroll_block_trees ();
+ reorder_blocks ();
end_alias_analysis ();
}
}
- /* The "last use" doesn't follow the "first use"?? */
- abort ();
+ /* The "last use" that was recorded can't be found after the first
+ use. This can happen when the last use was deleted while
+ processing an inner loop, this inner loop was then completely
+ unrolled, and the outer loop is always exited after the inner loop,
+ so that everything after the first use becomes a single basic block. */
+ return 1;
}
\f
/* Compute the benefit of eliminating the insns in the block whose
rtx x, y;
struct movable *movables;
{
- int xn = REGNO (x);
- int yn = REGNO (y);
+ unsigned int xn = REGNO (x);
+ unsigned int yn = REGNO (y);
struct movable *mx, *my;
for (mx = movables; mx; mx = mx->next)
int n_sets;
rtx reg, insn;
{
- register rtx p = insn;
- register int regno = REGNO (reg);
+ rtx p = insn;
+ unsigned int regno = REGNO (reg);
rtx temp;
/* Number of sets we have to insist on finding after INSN. */
int count = n_sets - 1;
/* Givs made from biv increments are always splittable for loop unrolling.
Since there is no regscan info for them, we have to keep track of them
separately. */
-int first_increment_giv, last_increment_giv;
+unsigned int first_increment_giv, last_increment_giv;
/* Communication with routines called via `note_stores'. */
&& CONSTANT_P (XEXP (src, 1))
&& ((increment = biv_total_increment (bl)) != NULL_RTX))
{
- int regno = REGNO (XEXP (src, 0));
+ unsigned int regno = REGNO (XEXP (src, 0));
for (bl2 = loop_iv_list; bl2; bl2 = bl2->next)
if (bl2->regno == regno)
markers. */
if (n_extra_increment && ! loop_info->has_volatile)
{
- int nregs = first_increment_giv + n_extra_increment;
+ unsigned int nregs = first_increment_giv + n_extra_increment;
/* Reallocate reg_iv_type and reg_iv_info. */
VARRAY_GROW (reg_iv_type, nregs);
if (set && GET_CODE (SET_DEST (set)) == REG)
{
- int regno = REGNO (SET_DEST (set));
+ unsigned int regno = REGNO (SET_DEST (set));
if (regno < max_reg_before_loop
&& REG_IV_TYPE (regno) == GENERAL_INDUCT
if (loop_mems_idx == 0)
return;
+ /* Find start of the extended basic block that enters the loop. */
+ for (p = loop->start;
+ PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
+ p = PREV_INSN (p))
+ ;
+
+ cselib_init ();
+
+ /* Build table of mems that get set to constant values before the
+ loop. */
+ for (; p != loop->start; p = NEXT_INSN (p))
+ cselib_process_insn (p);
+
/* Check to see if it's possible that some instructions in the
loop are never executed. */
for (p = next_insn_in_loop (loop, loop->scan_start);
loop_mems[i].optimize = 0;
else
{
- int j;
- rtx set;
-
/* Load the memory immediately before LOOP->START, which is
the NOTE_LOOP_BEG. */
- set = gen_move_insn (reg, mem);
- emit_insn_before (set, loop->start);
+ cselib_val *e = cselib_lookup (mem, VOIDmode, 0);
+ rtx set;
+ rtx best = mem;
+ int j;
+ struct elt_loc_list *const_equiv = 0;
+
+ if (e)
+ {
+ struct elt_loc_list *equiv;
+ struct elt_loc_list *best_equiv = 0;
+ for (equiv = e->locs; equiv; equiv = equiv->next)
+ {
+ if (CONSTANT_P (equiv->loc))
+ const_equiv = equiv;
+ else if (GET_CODE (equiv->loc) == REG)
+ best_equiv = equiv;
+ }
+ /* Use the constant equivalence if that is cheap enough. */
+ if (! best_equiv)
+ best_equiv = const_equiv;
+ else if (const_equiv
+ && (rtx_cost (const_equiv->loc, SET)
+ <= rtx_cost (best_equiv->loc, SET)))
+ {
+ best_equiv = const_equiv;
+ const_equiv = 0;
+ }
+
+ /* If best_equiv is nonzero, we know that MEM is set to a
+ constant or register before the loop. We will use this
+ knowledge to initialize the shadow register with that
+ constant or reg rather than by loading from MEM. */
+ if (best_equiv)
+ best = copy_rtx (best_equiv->loc);
+ }
+ set = gen_move_insn (reg, best);
+ set = emit_insn_before (set, loop->start);
+ if (const_equiv)
+ REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
+ copy_rtx (const_equiv->loc),
+ REG_NOTES (set));
if (written)
{
JUMP_LABEL (p) = label;
}
}
+
+ cselib_finish ();
}
/* For communication between note_reg_stored and its caller. */
There must be exactly one insn that sets this pseudo; it will be
deleted if all replacements succeed and we can prove that the register
is not used after the loop. */
+
static void
try_copy_prop (loop, replacement, regno)
const struct loop *loop;
rtx replacement;
- int regno;
+ unsigned int regno;
{
/* This is the reg that we are copying from. */
rtx reg_rtx = regno_reg_rtx[regno];