/* Perform doloop optimizations
- Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "flags.h"
#include "expr.h"
#include "basic-block.h"
#include "toplev.h"
#include "tm_p.h"
+#include "cfgloop.h"
/* This module is used to modify loops with a determinable number of
#ifdef HAVE_doloop_end
-static rtx doloop_condition_get
- PARAMS ((rtx));
-static unsigned HOST_WIDE_INT doloop_iterations_max
- PARAMS ((const struct loop_info *, enum machine_mode, int));
-static int doloop_valid_p
- PARAMS ((const struct loop *, rtx));
-static int doloop_modify
- PARAMS ((const struct loop *, rtx, rtx, rtx, rtx, rtx));
-static int doloop_modify_runtime
- PARAMS ((const struct loop *, rtx, rtx, rtx, enum machine_mode, rtx));
+static rtx doloop_condition_get (rtx);
+static unsigned HOST_WIDE_INT doloop_iterations_max (const struct loop_info *,
+ enum machine_mode, int);
+static int doloop_valid_p (const struct loop *, rtx);
+static int doloop_modify (const struct loop *, rtx, rtx, rtx, rtx, rtx);
+static int doloop_modify_runtime (const struct loop *, rtx, rtx, rtx,
+ enum machine_mode, rtx);
/* Return the loop termination condition for PATTERN or zero
if it is not a decrement and branch jump insn. */
static rtx
-doloop_condition_get (pattern)
- rtx pattern;
+doloop_condition_get (rtx pattern)
{
rtx cmp;
rtx inc;
MODE is the mode of the iteration count and NONNEG is nonzero if
the iteration count has been proved to be non-negative. */
static unsigned HOST_WIDE_INT
-doloop_iterations_max (loop_info, mode, nonneg)
- const struct loop_info *loop_info;
- enum machine_mode mode;
- int nonneg;
+doloop_iterations_max (const struct loop_info *loop_info,
+ enum machine_mode mode, int nonneg)
{
unsigned HOST_WIDE_INT n_iterations_max;
enum rtx_code code;
/* Return nonzero if the loop specified by LOOP is suitable for
the use of special low-overhead looping instructions. */
static int
-doloop_valid_p (loop, jump_insn)
- const struct loop *loop;
- rtx jump_insn;
+doloop_valid_p (const struct loop *loop, rtx jump_insn)
{
const struct loop_info *loop_info = LOOP_INFO (loop);
condition at run-time and have an additional jump around the loop
to ensure an infinite loop. */
if (loop_info->comparison_code == NE
+ && !loop_info->preconditioned
&& INTVAL (loop_info->increment) != -1
&& INTVAL (loop_info->increment) != 1)
{
low-overhead looping insn to emit at the end of the loop. This
returns nonzero if it was successful. */
static int
-doloop_modify (loop, iterations, iterations_max,
- doloop_seq, start_label, condition)
- const struct loop *loop;
- rtx iterations;
- rtx iterations_max;
- rtx doloop_seq;
- rtx start_label;
- rtx condition;
+doloop_modify (const struct loop *loop, rtx iterations, rtx iterations_max,
+ rtx doloop_seq, rtx start_label, rtx condition)
{
rtx counter_reg;
rtx count;
count = GEN_INT (INTVAL (count) - 1);
else
count = expand_simple_binop (GET_MODE (counter_reg), MINUS,
- count, GEN_INT (1),
+ count, const1_rtx,
0, 0, OPTAB_LIB_WIDEN);
}
number of loop iterations. DOLOOP_INSN is the low-overhead looping
insn to insert. Returns nonzero if loop successfully modified. */
static int
-doloop_modify_runtime (loop, iterations_max,
- doloop_seq, start_label, mode, condition)
- const struct loop *loop;
- rtx iterations_max;
- rtx doloop_seq;
- rtx start_label;
- enum machine_mode mode;
- rtx condition;
+doloop_modify_runtime (const struct loop *loop, rtx iterations_max,
+ rtx doloop_seq, rtx start_label,
+ enum machine_mode mode, rtx condition)
{
const struct loop_info *loop_info = LOOP_INFO (loop);
HOST_WIDE_INT abs_inc;
If the loop has been unrolled, the full calculation is
- t1 = abs_inc * unroll_number; increment per loop
- n = abs (final - initial) / t1; full loops
- n += (abs (final - initial) % t1) != 0; partial loop
+ t1 = abs_inc * unroll_number; increment per loop
+ n = (abs (final - initial) + abs_inc - 1) / t1; full loops
+ n += (abs (final - initial) + abs_inc - 1) % t1) >= abs_inc;
+ partial loop
+ which works out to be equivalent to
- However, in certain cases the unrolled loop will be preconditioned
- by emitting copies of the loop body with conditional branches,
- so that the unrolled loop is always a full loop and thus needs
- no exit tests. In this case we don't want to add the partial
- loop count. As above, when t1 is a power of two we don't need to
- worry about overflow.
+ n = (abs (final - initial) + t1 - 1) / t1;
+
+ In the case where the loop was preconditioned, a few iterations
+ may have been executed earlier; but 'initial' was adjusted as they
+ were executed, so we don't need anything special for that case here.
+ As above, when t1 is a power of two we don't need to worry about
+ overflow.
The division and modulo operations can be avoided by requiring
that the increment is a power of 2 (precondition_loop_p enforces
if (shift_count < 0)
abort ();
- if (!loop_info->preconditioned)
- diff = expand_simple_binop (GET_MODE (diff), PLUS,
- diff, GEN_INT (abs_loop_inc - 1),
- diff, 1, OPTAB_LIB_WIDEN);
+ /* (abs (final - initial) + abs_inc * unroll_number - 1) */
+ diff = expand_simple_binop (GET_MODE (diff), PLUS,
+ diff, GEN_INT (abs_loop_inc - 1),
+ diff, 1, OPTAB_LIB_WIDEN);
/* (abs (final - initial) + abs_inc * unroll_number - 1)
/ (abs_inc * unroll_number) */
is a candidate for this optimization. Returns nonzero if loop
successfully modified. */
int
-doloop_optimize (loop)
- const struct loop *loop;
+doloop_optimize (const struct loop *loop)
{
struct loop_info *loop_info = LOOP_INFO (loop);
rtx initial_value;