/* Try to unroll loops, and split induction variables.
- Copyright (C) 1992, 93-95, 97-99, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
This file is part of GNU CC.
#include "expr.h"
#include "loop.h"
#include "toplev.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
/* This controls which loops are unrolled, and by how much we unroll
them. */
/* Forward declarations. */
static void init_reg_map PARAMS ((struct inline_remap *, int));
-static rtx calculate_giv_inc PARAMS ((rtx, rtx, int));
+static rtx calculate_giv_inc PARAMS ((rtx, rtx, unsigned int));
static rtx initial_reg_note_copy PARAMS ((rtx, struct inline_remap *));
static void final_reg_note_copy PARAMS ((rtx, struct inline_remap *));
static void copy_loop_body PARAMS ((rtx, rtx, struct inline_remap *, rtx, int,
int strength_reduce_p;
{
int i, j;
+ unsigned int r;
unsigned HOST_WIDE_INT temp;
int unroll_number = 1;
rtx copy_start, copy_end;
struct inline_remap *map;
char *local_label = NULL;
char *local_regno;
- int max_local_regnum;
- int maxregnum;
+ unsigned int max_local_regnum;
+ unsigned int maxregnum;
rtx exit_label = 0;
rtx start_label;
struct iv_class *bl;
int splitting_not_safe = 0;
- enum unroll_types unroll_type;
+ enum unroll_types unroll_type = UNROLL_NAIVE;
int loop_preconditioned = 0;
rtx safety_label;
/* This points to the last real insn in the loop, which should be either
return;
}
else if (loop_info->n_iterations > 0
+ /* Avoid overflow in the next expression. */
+ && loop_info->n_iterations < MAX_UNROLLED_INSNS
&& loop_info->n_iterations * insn_count < MAX_UNROLLED_INSNS)
{
unroll_number = loop_info->n_iterations;
/* Default case, calculate number of times to unroll loop based on its
size. */
- if (unroll_number == 1)
+ if (unroll_type == UNROLL_NAIVE)
{
if (8 * insn_count < MAX_UNROLLED_INSNS)
unroll_number = 8;
unroll_number = 4;
else
unroll_number = 2;
-
- unroll_type = UNROLL_NAIVE;
}
/* Now we know how many times to unroll the loop. */
results in better code. */
/* We must limit the generic test to max_reg_before_loop, because only
these pseudo registers have valid regno_first_uid info. */
- for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; ++j)
- if (REGNO_FIRST_UID (j) > 0 && REGNO_FIRST_UID (j) <= max_uid_for_loop
- && uid_luid[REGNO_FIRST_UID (j)] >= copy_start_luid
- && REGNO_LAST_UID (j) > 0 && REGNO_LAST_UID (j) <= max_uid_for_loop
- && uid_luid[REGNO_LAST_UID (j)] <= copy_end_luid)
+ for (r = FIRST_PSEUDO_REGISTER; r < max_reg_before_loop; ++r)
+ if (REGNO_FIRST_UID (r) > 0 && REGNO_FIRST_UID (r) <= max_uid_for_loop
+ && uid_luid[REGNO_FIRST_UID (r)] >= copy_start_luid
+ && REGNO_LAST_UID (r) > 0 && REGNO_LAST_UID (r) <= max_uid_for_loop
+ && uid_luid[REGNO_LAST_UID (r)] <= copy_end_luid)
{
/* However, we must also check for loop-carried dependencies.
If the value the pseudo has at the end of iteration X is
regno_last_uid. */
/* ??? This check is simplistic. We would get better code if
this check was more sophisticated. */
- if (set_dominates_use (j, REGNO_FIRST_UID (j), REGNO_LAST_UID (j),
+ if (set_dominates_use (r, REGNO_FIRST_UID (r), REGNO_LAST_UID (r),
copy_start, copy_end))
- local_regno[j] = 1;
+ local_regno[r] = 1;
if (loop_dump_stream)
{
- if (local_regno[j])
- fprintf (loop_dump_stream, "Marked reg %d as local\n", j);
+ if (local_regno[r])
+ fprintf (loop_dump_stream, "Marked reg %d as local\n", r);
else
fprintf (loop_dump_stream, "Did not mark reg %d as local\n",
- j);
+ r);
}
}
/* Givs that have been created from multiple biv increments always have
local registers. */
- for (j = first_increment_giv; j <= last_increment_giv; j++)
+ for (r = first_increment_giv; r <= last_increment_giv; r++)
{
- local_regno[j] = 1;
+ local_regno[r] = 1;
if (loop_dump_stream)
- fprintf (loop_dump_stream, "Marked reg %d as local\n", j);
+ fprintf (loop_dump_stream, "Marked reg %d as local\n", r);
}
}
map->reg_map = (rtx *) xmalloc (maxregnum * sizeof (rtx));
VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray, maxregnum,
- "unroll_loop");
+ "unroll_loop_precondition");
global_const_equiv_varray = map->const_equiv_varray;
init_reg_map (map, maxregnum);
if (local_label[j])
set_label_in_map (map, j, gen_label_rtx ());
- for (j = FIRST_PSEUDO_REGISTER; j < max_local_regnum; j++)
- if (local_regno[j])
+ for (r = FIRST_PSEUDO_REGISTER; r < max_local_regnum; r++)
+ if (local_regno[r])
{
- map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
- record_base_value (REGNO (map->reg_map[j]),
- regno_reg_rtx[j], 0);
+ map->reg_map[r]
+ = gen_reg_rtx (GET_MODE (regno_reg_rtx[r]));
+ record_base_value (REGNO (map->reg_map[r]),
+ regno_reg_rtx[r], 0);
}
/* The last copy needs the compare/branch insns at the end,
so reset copy_end here if the loop ends with a conditional
if (local_label[j])
set_label_in_map (map, j, gen_label_rtx ());
- for (j = FIRST_PSEUDO_REGISTER; j < max_local_regnum; j++)
- if (local_regno[j])
+ for (r = FIRST_PSEUDO_REGISTER; r < max_local_regnum; r++)
+ if (local_regno[r])
{
- map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
- record_base_value (REGNO (map->reg_map[j]),
- regno_reg_rtx[j], 0);
+ map->reg_map[r] = gen_reg_rtx (GET_MODE (regno_reg_rtx[r]));
+ record_base_value (REGNO (map->reg_map[r]),
+ regno_reg_rtx[r], 0);
}
/* If loop starts with a branch to the test, then fix it so that
static rtx
calculate_giv_inc (pattern, src_insn, regno)
rtx pattern, src_insn;
- int regno;
+ unsigned int regno;
{
rtx increment;
rtx increment_total = 0;
{
struct iv_class *bl;
struct induction *v, *tv;
- int regno = REGNO (SET_DEST (set));
+ unsigned int regno = REGNO (SET_DEST (set));
v = addr_combined_regs[REGNO (SET_DEST (set))];
bl = reg_biv_class[REGNO (v->src_reg)];
&& GET_CODE (SET_DEST (set)) == REG
&& splittable_regs[REGNO (SET_DEST (set))])
{
- int regno = REGNO (SET_DEST (set));
- int src_regno;
+ unsigned int regno = REGNO (SET_DEST (set));
+ unsigned int src_regno;
dest_reg_was_split = 1;
#endif
splittable_regs[regno]
- = GEN_INT (INTVAL (giv_inc)
- + INTVAL (splittable_regs[src_regno]));
+ = simplify_gen_binary (PLUS, GET_MODE (giv_src_reg),
+ giv_inc,
+ splittable_regs[src_regno]);
giv_inc = splittable_regs[regno];
/* Now split the induction variable by changing the dest
if (JUMP_LABEL (insn) == start_label && insn == copy_end
&& ! last_iteration)
{
+ /* Update JUMP_LABEL correctly to make invert_jump working. */
+ JUMP_LABEL (copy) = get_label_from_map (map,
+ CODE_LABEL_NUMBER
+ (JUMP_LABEL (insn)));
/* This is a branch to the beginning of the loop; this is the
last insn being copied; and this is not the last iteration.
In this case, we want to change the original fall through
case to be a branch past the end of the loop, and the
original jump label case to fall_through. */
- if (invert_exp (pattern, copy))
- {
- if (! redirect_exp (&pattern,
- get_label_from_map (map,
- CODE_LABEL_NUMBER
- (JUMP_LABEL (insn))),
- exit_label, copy))
- abort ();
- }
- else
+ if (!invert_jump (copy, exit_label, 0))
{
rtx jmp;
rtx lab = gen_label_rtx ();
jmp = emit_barrier_after (jmp);
emit_label_after (lab, jmp);
LABEL_NUSES (lab) = 0;
- if (! redirect_exp (&pattern,
- get_label_from_map (map,
- CODE_LABEL_NUMBER
- (JUMP_LABEL (insn))),
- lab, copy))
- abort ();
+ if (!redirect_jump (copy, lab, 0))
+ abort();
}
}
/* If this used to be a conditional jump insn but whose branch
direction is now known, we must do something special. */
- if (condjump_p (insn) && !simplejump_p (insn) && map->last_pc_value)
+ if (any_condjump_p (insn) && onlyjump_p (insn) && map->last_pc_value)
{
#ifdef HAVE_cc0
/* If the previous insn set cc0 for us, delete it. */
this new block. */
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
&& ((NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)
static void
iteration_info (loop, iteration_var, initial_value, increment)
- const struct loop *loop;
+ const struct loop *loop ATTRIBUTE_UNUSED;
rtx iteration_var, *initial_value, *increment;
{
struct iv_class *bl;
{
if (GET_CODE (PATTERN (insn)) == RETURN)
break;
- else if (! simplejump_p (insn)
+ else if (!any_uncondjump_p (insn)
/* Prevent infinite loop following infinite loops. */
|| jump_count++ > 20)
return 0;