Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "rtl.h"
-#include "insn-flags.h"
#include "flags.h"
#include "expr.h"
#include "loop.h"
#include "hard-reg-set.h"
#include "basic-block.h"
+#include "toplev.h"
#include "tm_p.h"
statement within a loop will generate multiple loop exits.
Another example of a loop that currently generates multiple exit
targets is for (i = 0; i < (foo ? 8 : 4); i++) { }. */
- if (loop_info->has_multiple_exit_targets)
+ if (loop_info->has_multiple_exit_targets || loop->exit_count)
{
if (loop_dump_stream)
fprintf (loop_dump_stream,
fputs (" iterations).", loop_dump_stream);
}
+ /* Emit the label that will delimit the top of the loop.
+ This has to be done before the delete_insn call below, to prevent
+ delete_insn from deleting too much. */
+ emit_label_after (start_label, loop->top ? loop->top : loop->start);
+ LABEL_NUSES (start_label)++;
+
/* Discard original jump to continue loop. The original compare
result may still be live, so it cannot be discarded explicitly. */
delete_insn (jump_insn);
- /* Emit the label that will delimit the start of the loop. */
- emit_label_after (start_label, loop->start);
- LABEL_NUSES (start_label)++;
-
counter_reg = XEXP (condition, 0);
if (GET_CODE (counter_reg) == PLUS)
counter_reg = XEXP (counter_reg, 0);
if (GET_CODE (count) == CONST_INT)
count = GEN_INT (INTVAL (count) - 1);
else
- count = expand_binop (GET_MODE (counter_reg), sub_optab,
- count, GEN_INT (1),
- 0, 0, OPTAB_LIB_WIDEN);
+ count = expand_simple_binop (GET_MODE (counter_reg), MINUS,
+ count, GEN_INT (1),
+ 0, 0, OPTAB_LIB_WIDEN);
}
/* Insert initialization of the count register into the loop header. */
|| comparison_code == NE);
/* The number of iterations (prior to any loop unrolling) is given by:
- (abs (final - initial) + abs_inc - 1) / abs_inc.
+
+ n = (abs (final - initial) + abs_inc - 1) / abs_inc.
However, it is possible for the summation to overflow, and a
safer method is:
- abs (final - initial) / abs_inc + (abs (final - initial) % abs_inc) != 0
+ n = abs (final - initial) / abs_inc;
+ n += (abs (final - initial) % abs_inc) != 0;
If the loop has been unrolled, then the loop body has been
- preconditioned to iterate a multiple of unroll_number times.
- The number of iterations of the loop body is simply:
- abs (final - initial) / (abs_inc * unroll_number).
+ preconditioned to iterate a multiple of unroll_number times. If
+ abs_inc is != 1, the full calculation is
+
+ t1 = abs_inc * unroll_number;
+ n = abs (final - initial) / t1;
+ n += (abs (final - initial) % t1) > t1 - abs_inc;
The division and modulo operations can be avoided by requiring
that the increment is a power of 2 (precondition_loop_p enforces
start_sequence ();
/* abs (final - initial) */
- diff = expand_binop (mode, sub_optab,
- copy_rtx (neg_inc ? initial_value : final_value),
- copy_rtx (neg_inc ? final_value : initial_value),
- NULL_RTX, unsigned_p, OPTAB_LIB_WIDEN);
+ diff = expand_simple_binop (mode, MINUS,
+ copy_rtx (neg_inc ? initial_value : final_value),
+ copy_rtx (neg_inc ? final_value : initial_value),
+ NULL_RTX, unsigned_p, OPTAB_LIB_WIDEN);
- if (loop_info->unroll_number == 1)
+ if (abs_inc * loop_info->unroll_number != 1)
{
+ int shift_count;
+ rtx extra;
+ rtx label;
+ unsigned HOST_WIDE_INT limit;
+
+ shift_count = exact_log2 (abs_inc * loop_info->unroll_number);
+ if (shift_count < 0)
+ abort ();
+
+ /* abs (final - initial) / (abs_inc * unroll_number) */
+ iterations = expand_simple_binop (GET_MODE (diff), LSHIFTRT,
+ diff, GEN_INT (shift_count),
+ NULL_RTX, 1,
+ OPTAB_LIB_WIDEN);
+
if (abs_inc != 1)
{
- int shift_count;
- rtx extra;
- rtx label;
-
- shift_count = exact_log2 (abs_inc);
- if (shift_count < 0)
- abort ();
-
- /* abs (final - initial) / abs_inc */
- iterations = expand_binop (GET_MODE (diff), lshr_optab,
- diff, GEN_INT (shift_count),
- NULL_RTX, 1,
- OPTAB_LIB_WIDEN);
-
- /* abs (final - initial) % abs_inc */
- extra = expand_binop (GET_MODE (iterations), and_optab,
- diff, GEN_INT (abs_inc - 1),
- NULL_RTX, 1,
- OPTAB_LIB_WIDEN);
-
- /* If (abs (final - initial) % abs_inc == 0) jump past
- following increment instruction. */
+ /* abs (final - initial) % (abs_inc * unroll_number) */
+ rtx count = GEN_INT (abs_inc * loop_info->unroll_number - 1);
+ extra = expand_simple_binop (GET_MODE (iterations), AND,
+ diff, count, NULL_RTX, 1,
+ OPTAB_LIB_WIDEN);
+
+ /* If (abs (final - initial) % (abs_inc * unroll_number)
+ <= abs_inc * (unroll - 1)),
+ jump past following increment instruction. */
label = gen_label_rtx();
- emit_cmp_and_jump_insns (extra, const0_rtx, EQ, NULL_RTX,
+ limit = abs_inc * (loop_info->unroll_number - 1);
+ emit_cmp_and_jump_insns (extra, GEN_INT (limit),
+ limit == 0 ? EQ : LEU, NULL_RTX,
GET_MODE (extra), 0, 0, label);
JUMP_LABEL (get_last_insn ()) = label;
LABEL_NUSES (label)++;
/* Increment the iteration count by one. */
- iterations = expand_binop (GET_MODE (iterations), add_optab,
- iterations, GEN_INT (1),
- iterations, 1,
- OPTAB_LIB_WIDEN);
+ iterations = expand_simple_binop (GET_MODE (iterations), PLUS,
+ iterations, GEN_INT (1),
+ iterations, 1,
+ OPTAB_LIB_WIDEN);
emit_label (label);
}
- else
- iterations = diff;
}
else
- {
- int shift_count;
-
- /* precondition_loop_p has preconditioned the loop so that the
- iteration count of the loop body is always a power of 2.
- Since we won't get an overflow calculating the loop count,
- the code we emit is simpler. */
- shift_count = exact_log2 (loop_info->unroll_number * abs_inc);
- if (shift_count < 0)
- abort ();
-
- iterations = expand_binop (GET_MODE (diff), lshr_optab,
- diff, GEN_INT (shift_count),
- NULL_RTX, 1,
- OPTAB_LIB_WIDEN);
- }
-
+ iterations = diff;
/* If there is a NOTE_INSN_LOOP_VTOP, we have a `for' or `while'
style loop, with a loop exit test at the start. Thus, we can