/* Move constant computations out of loops.
   Copyright (C) 1987, 1988 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.  No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing.  Refer to the GNU CC General Public
License for full details.

Everyone is granted permission to copy, modify and redistribute
GNU CC, but only under the conditions described in the
GNU CC General Public License.   A copy of this license is
supposed to have been given to you along with GNU CC so you
can know your rights and responsibilities.  It should be in a
file named COPYING.  Among other things, the copyright notice
and this notice must be preserved on all copies.  */


/* This is the loop optimization pass of the compiler.
   It finds invariant computations within loops and moves them
   to the beginning of the loop.  Then it identifies basic and 
   general induction variables.  Strength reduction is applied to the general
   induction variables, and induction variable elimination is applied to
   the basic induction variables.

   It also finds cases where
   a register is set within the loop by zero-extending a narrower value
   and changes these to zero the entire register once before the loop
   and merely copy the low part within the loop.

   Most of the complexity is in heuristics to decide when it is worth
   while to do these things.  */

/* ??? verify_loop would run faster if we made one table
   of the minimum and maximum luids from which each label is reached.
   Also, it would be faster if loop_store_addrs were a hash table.  */

#include "config.h"
#include "rtl.h"
#include "expr.h"
#include "insn-config.h"
#include "regs.h"
#include "recog.h"
#include "flags.h"
#include <stdio.h>

/* Vector mapping INSN_UIDs to luids.
   The luids are like uids but increase monononically always.
   We use them to see whether a jump comes from outside a given loop.  */

static short *uid_luid;

/* Get the luid of an insn.  */

#define INSN_LUID(INSN) (uid_luid[INSN_UID (INSN)])

/* 1 + largest uid of any insn.  */

static int max_uid;

/* 1 + luid of last insn.  */

static int max_luid;

/* Nonzero if somewhere in the current loop
   there is either a subroutine call,
   or a store into a memory address that is not fixed,
   or a store in a BLKmode memory operand,
   or too many different fixed addresses stored in
   to record them all in `loop_store_addrs'.

   In any of these cases, no memory location can be regarded
   as invariant.  */

static int unknown_address_altered;

/* Nonzero if somewhere in the current loop there is a store
   into a memory address that is not fixed but is known to be
   part of an aggregate.

   In this case, no memory reference in an aggregate may be
   considered invariant.  */

static int unknown_aggregate_altered;

/* Nonzero if somewhere in the current loop there is a store
   into a memory address other than a fixed address not in an aggregate.

   In this case, no memory reference in an aggregate at a varying address
   may be considered invariant.  */

static int fixed_aggregate_altered;

/* Nonzero if there is a subroutine call in the current loop.
   (unknown_address_altered is also nonzero in this case.)  */

static int loop_has_call;

/* Indexed by register number, contains the number of times the reg
   is set during the loop being scanned.
   During code motion, -1 indicates a reg that has been made a candidate.
   After code motion, regs moved have 0 (which is accurate now)
   while the failed candidates have the original number of times set.

   Therefore, at all times, 0 indicates an invariant register;
   -1 a conditionally invariant one.  */

static short *n_times_set;

/* Original value of n_times_set; same except that this value
   is not set to -1 for a reg whose sets have been made candidates
   and not set to 0 for a reg that is moved.  */

static short *n_times_used;

/* Array of fixed memory addresses that are stored in this loop.
   If there are too many to fit here,
   we just turn on unknown_address_altered.  */

#define NUM_STORES 10
static rtx loop_store_addrs[NUM_STORES];
static int loop_store_widths[NUM_STORES];

/* Index of first available slot in above array.  */
static int loop_store_addrs_idx;

/* Count of movable (i.e. invariant) instructions discovered in the loop.  */
static int num_movables;

/* Count of memory write instructions discovered in the loop.  */
static int num_mem_sets;

/* Number of loops contained within the current one, including itself.  */
static int loops_enclosed;

/* Bound on pseudo register number before loop optimization.
   A pseudo has valid regscan info if its number is < old_max_reg.  */
static int old_max_reg;

/* During the analysis of a loop, a chain of `struct movable's
   is made to record all the movable insns found.
   Then the entire chain can be scanned to decide which to move.  */

struct movable
{
  rtx insn;			/* A movable insn */
  rtx set_src;                  /* The expression this reg is set from.
				   Either SET_SRC (body) or a REG_EQUAL.  */
  int consec;			/* Number of consecutive following insns 
				   that must be moved with this one.  */
  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.  */
  short savings;		/* Number of insns we can move for this reg,
				   including other movables that force this
				   or match this one.  */
  unsigned int cond : 1;	/* 1 if only conditionally movable */
  unsigned int force : 1;	/* 1 means MUST move this insn */
  unsigned int global : 1;	/* 1 means reg is live outside this loop */
  unsigned int done : 1;	/* 1 inhibits further processing of this */
  unsigned int partial : 1;	/* Moving this doesn't make it invariant.  */
  struct movable *match;	/* First entry for same value */
  struct movable *forces;	/* An insn that must be moved if this is */
  struct movable *next;
};

static FILE *loop_dump_stream;

static rtx verify_loop ();
static int invariant_p ();
static int consec_sets_invariant_p ();
static int can_jump_into_range_p ();
static void count_loop_regs_set ();
static void note_addr_stored ();
static int loop_reg_used_before_p ();
static void constant_high_bytes ();
static void scan_loop ();
static rtx replace_regs ();
static void replace_call_address ();
static void move_movables ();
static int may_trap_p ();
static void strength_reduce ();
static void find_mem_givs ();
static void record_giv ();
static void delete_insn_forces ();
static int basic_induction_var ();
static int general_induction_var ();
static int consec_sets_giv ();
static int check_dbra_loop ();
static void emit_iv_init_code ();
static int product_cheap_p ();
static void emit_iv_inc ();
static int can_eliminate_biv_p ();
static void eliminate_biv ();
static rtx final_biv_value ();

/* Entry point of this file.  Perform loop optimization
   on the current function.  F is the first insn of the function
   and NREGS is the number of register numbers used.  */

void
loop_optimize (f, dumpfile)
     /* f is the first instruction of a chain of insns for one function */
     rtx f;
     FILE *dumpfile;
{
  register rtx insn;
  register int i;
  rtx end;
  rtx last_insn;

  loop_dump_stream = dumpfile;

  init_recog ();

  old_max_reg = max_reg_num ();

  /* First find the last real insn, and count the number of insns,
     and assign insns their suids.  */

  for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
    if (INSN_UID (insn) > i)
      i = INSN_UID (insn);

  max_uid = i + 1;
  uid_luid = (short *) alloca ((i + 1) * sizeof (short));
  bzero (uid_luid, (i + 1) * sizeof (short));

  /* Compute the mapping from uids to luids.
     LUIDs are numbers assigned to insns, like uids,
     except that luids increase monotonically through the code.  */

  for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
    {
      last_insn = insn;
      INSN_LUID (insn) = ++i;
    }

  max_luid = i;

  /* Don't leave gaps in uid_luid for insns that have been
     deleted.  It is possible that the first or last insn
     using some register has been deleted by cross-jumping.
     Make sure that uid_luid for that former insn's uid
     points to the general area where that insn used to be.  */
  for (i = 0; i < max_uid; i++)
    {
      uid_luid[0] = uid_luid[i];
      if (uid_luid[0] != 0)
	break;
    }
  for (i = 0; i < max_uid; i++)
    if (uid_luid[i] == 0)
      uid_luid[i] = uid_luid[i - 1];

  /* Find and process each loop.
     We scan from the end, and process each loop when its start is seen,
     so we process innermost loops first.  */

  for (insn = last_insn; insn; insn = PREV_INSN (insn))
    if (GET_CODE (insn) == NOTE
	&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
      {
	/* Make sure it really is a loop -- no jumps in from outside.  */
	end = verify_loop (f, insn);
	if (end != 0)
	  /* If so, optimize this loop.  */
	  scan_loop (insn, end, max_reg_num ());
	else if (loop_dump_stream)
	  fprintf (loop_dump_stream,
		   "\nLoop at %d ignored due to multiple entry points.\n",
		   INSN_UID (insn));
      }
}

/* Optimize one loop whose start is LOOP_START and end is END.
   LOOP_START is the NOTE_INSN_LOOP_BEG and END is the matching
   NOTE_INSN_LOOP_END.  */

/* ??? can also move memory writes out of loop if destination
   address is invariant? */

static void
scan_loop (loop_start, end, nregs)
     rtx loop_start, end;
     int nregs;
{
  register int i;
  register rtx p = NEXT_INSN (loop_start);
  /* 1 if we are scanning insns that could be executed zero times.  */
  int maybe_never = 0;
  /* 1 if we are scanning insns that might never be executed
     due to a subroutine call which might exit before they are reached.  */
  int call_passed = 0;
  /* For a rotated loop that is entered near the bottom,
     this is the label at the top.  Otherwise it is zero.  */
  rtx loop_top = 0;
  /* This is the insn (whatever kind) before the NOTE that starts the loop.
     Any insns moved out of the loop will follow it.  */
  rtx before_start = PREV_INSN (loop_start);
  /* Jump insn that enters the loop, or 0 if control drops in.  */
  rtx loop_entry_jump = 0;
  /* Place in the loop where control enters.  */
  rtx scan_start;
  /* Number of insns in the loop.  */
  int insn_count;
  int tem;
  rtx temp;
  /* Indexed by register number, contains 1 for a register whose
     assignments may not be moved out of the loop.  */
  char *may_not_move;
  /* Chain describing insns movable in current loop.  */
  struct movable *movables = 0;
  /* Last element in `movables' -- so we can add elements at the end.  */
  struct movable *last_movable = 0;
  /* Ratio of extra register life span we can justify
     for saving an instruction.  More if loop doesn't call subroutines
     since in that case saving an insn makes more difference
     and more registers are available.  */
  int threshold = loop_has_call ? 15 : 30;
  /* Nonzero if the insn that jumps into the real loop
     is not the very first thing after the loop-beginning note.  */
  int something_before_entry_jump = 0;

  n_times_set = (short *) alloca (nregs * sizeof (short));
  n_times_used = (short *) alloca (nregs * sizeof (short));
  may_not_move = (char *) alloca (nregs);

  /* Determine whether this loop starts with a jump down
     to a test at the end.  */
  while (p != end
	 && GET_CODE (p) != CODE_LABEL && GET_CODE (p) != JUMP_INSN)
    {
      if (GET_CODE (p) == CALL_INSN || GET_CODE (p) == INSN)
	something_before_entry_jump = 1;
      p = NEXT_INSN (p);
    }

  /* "Loop" contains neither jumps nor labels;
     it must have been a dummy.  Think no more about it.  */
  if (p == end)
    return;

  scan_start = p;

  /* If loop has a jump before the first label,
     the true entry is the target of that jump.
     Start scan from there.
     But record in LOOP_TOP the place where the end-test jumps
     back to so we can scan that after the end of the loop.  */
  if (GET_CODE (p) == JUMP_INSN)
    {
      loop_entry_jump = p;
      loop_top = NEXT_INSN (p);
      /* Loop entry will never be a conditional jump.
	 If we see one, this must not be a real loop.
	 Also, a return-insn isn't a jump to enter the loop.  */
      if (GET_CODE (loop_top) != BARRIER
	  || GET_CODE (PATTERN (p)) != SET)
	return;
      /* Get the label at which the loop is entered.  */
      p = XEXP (SET_SRC (PATTERN (p)), 0);
      /* Check to see whether the jump actually
	 jumps out of the loop (meaning it's no loop).
	 This case can happen for things like
	 do {..} while (0).  */
      if (p == 0
	  || INSN_LUID (p) < INSN_LUID (loop_start)
	  || INSN_LUID (p) >= INSN_LUID (end))
	{
	  if (loop_dump_stream)
	    fprintf (loop_dump_stream, "\nLoop from %d to %d is phony.\n\n",
		     INSN_UID (loop_start), INSN_UID (end));
	  return;
	}

      /* Find the first label after the entry-jump.  */
      while (GET_CODE (loop_top) != CODE_LABEL)
	{
	  loop_top = NEXT_INSN (loop_top);
	  if (loop_top == 0)
	    abort ();
	}

      /* Maybe rearrange the loop to drop straight in
	 with a new test to jump around it entirely.
	 (The latter is considered outside the loop.)
	 If this is done, we no longer enter with a jump.  */
      if (! something_before_entry_jump
	  && loop_skip_over (loop_start, end, loop_entry_jump))
	{
	  scan_start = loop_top;
	  loop_top = 0;
	}
      else
	/* We really do enter with a jump;
	   scan the loop from the place where the jump jumps to.  */
	scan_start = p;
    }

  /* Count number of times each reg is set during this loop.
     Set MAY_NOT_MOVE[I] if it is not safe to move out
     the setting of register I.  */

  bzero (n_times_set, nregs * sizeof (short));
  bzero (may_not_move, nregs);
  count_loop_regs_set (loop_top ? loop_top : loop_start, end,
		       may_not_move, &insn_count, nregs);
  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    may_not_move[i] = 1, n_times_set[i] = 1;
  bcopy (n_times_set, n_times_used, nregs * sizeof (short));

  if (loop_dump_stream)
    fprintf (loop_dump_stream, "\nLoop from %d to %d: %d real insns\n\n",
	     INSN_UID (loop_start), INSN_UID (end), insn_count);

  /* Scan through the loop finding insns that are safe to move.
     In each such insn, store QImode as the mode, to mark it.
     Then set n_times_set to -1 for the reg being set, so that
     this reg will be considered invariant for subsequent insns.
     We consider whether subsequent insns use the reg
     in deciding whether it is worth actually moving.

     MAYBE_NEVER is nonzero if we have passed a conditional jump insn
     and therefore it is possible that the insns we are scanning
     would never be executed.  At such times, we must make sure
     that it is safe to execute the insn once instead of zero times.
     When MAYBE_NEVER is 0, all insns will be executed at least once
     so that is not a problem.  */

  p = scan_start;
  while (1)
    {
      p = NEXT_INSN (p);
      /* At end of a straight-in loop, we are done.
	 At end of a loop entered at the bottom, scan the top.  */
      if (p == scan_start)
	break;
      if (p == end)
	{
	  if (loop_top != 0)
	    p = NEXT_INSN (loop_top);
	  else
	    break;
	  if (p == scan_start)
	    break;
	}
      if (GET_CODE (p) == INSN
	  && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG
	  && ! may_not_move[REGNO (SET_DEST (PATTERN (p)))])
	{
	  int tem1 = 0;
	  /* If this register is used or set outside the loop,
	     then we can move it only if we know this insn is
	     executed exactly once per iteration,
	     and we can check all the insns executed before it
	     to make sure none of them used the value that
	     was lying around at entry to the loop.  */
	  /* Make sure that regscan info exists for this register;
	     it must be less than old_max_reg.  */
	  if ((REGNO (SET_DEST (PATTERN (p))) >= old_max_reg
	       || uid_luid[regno_last_uid[REGNO (SET_DEST (PATTERN (p)))]] > INSN_LUID (end)
	       || uid_luid[regno_first_uid[REGNO (SET_DEST (PATTERN (p)))]] < INSN_LUID (loop_start))
	      && (maybe_never
		  || loop_reg_used_before_p (p, loop_start, scan_start, end)))
	    ;
	  else if (((tem = invariant_p (SET_SRC (PATTERN (p))))
		    || ((temp = find_reg_note (p, REG_EQUAL, 0)) 
			&& (tem = invariant_p (XEXP (temp, 0)))))
		   && (n_times_set[REGNO (SET_DEST (PATTERN (p)))] == 1
		       || (tem1
			   = consec_sets_invariant_p (SET_DEST (PATTERN (p)),
						      n_times_set[REGNO (SET_DEST (PATTERN (p)))],
						      p)))
		   /* If the insn can cause a trap (such as divide by zero),
		      can't move it unless it's guaranteed to be executed
		      once loop is entered.  Even a function call might
		      prevent the trap insn from being reached
		      (since it might exit!)  */
		   && ! ((maybe_never || call_passed)
			 && (may_trap_p (SET_SRC (PATTERN (p)))
			     || ((temp = find_reg_note (p, REG_EQUAL, 0))
				 && may_trap_p (XEXP (temp, 0))))))
	    {
	      register struct movable *m;
	      register int regno = REGNO (SET_DEST (PATTERN (p)));
	      int count;
	      m = (struct movable *) alloca (sizeof (struct movable));
	      m->next = 0;
	      m->insn = p;
	      temp = find_reg_note (p, REG_EQUAL, 0);
	      if (temp)
		m->set_src = XEXP (temp, 0);
	      else
		m->set_src = SET_SRC (PATTERN (p));
	      m->force = 0;
	      m->consec = n_times_set[REGNO (SET_DEST (PATTERN (p)))] - 1;
	      m->done = 0;
	      m->forces = 0;
	      m->partial = 0;
	      m->regno = regno;
	      /* Set M->cond if either invariant_p or consec_sets_invariant_p
		 returned 2 (only conditionally invariant).  */
	      m->cond = ((tem | tem1) > 1);
	      m->global = (uid_luid[regno_last_uid[regno]] > INSN_LUID (end)
			   || uid_luid[regno_first_uid[regno]] < INSN_LUID (loop_start));
	      m->match = 0;
	      m->lifetime = (uid_luid[regno_last_uid[regno]]
			     - uid_luid[regno_first_uid[regno]]);
	      m->savings = n_times_used[regno];
	      n_times_set[regno] = -1;
	      /* Add M to the end of the chain MOVABLES.  */
	      if (movables == 0)
		movables = m;
	      else
		last_movable->next = m;
	      last_movable = m;
	      /* Skip the consecutive insns, if there are any.  */
	      for (count = m->consec - 1; count >= 0; count--)
		{
		  do p = NEXT_INSN (p);
		  while (GET_CODE (p) == NOTE);
		}
	    }
	  /* If this register is always set within a STRICT_LOW_PART
	     or set to zero, then its high bytes are constant.
	     So clear them outside the loop and within the loop
	     just load the low bytes.
	     We must check that the machine has an instruction to do so.
	     Also, if the value loaded into the register
	     depends on the same register, this cannot be done.  */
	  else if (SET_SRC (PATTERN (p)) == const0_rtx
		   && GET_CODE (NEXT_INSN (p)) == INSN
		   && GET_CODE (PATTERN (NEXT_INSN (p))) == SET
		   && (GET_CODE (SET_DEST (PATTERN (NEXT_INSN (p))))
		       == STRICT_LOW_PART)
		   && (GET_CODE (XEXP (SET_DEST (PATTERN (NEXT_INSN (p))), 0))
		       == SUBREG)
		   && (SUBREG_REG (XEXP (SET_DEST (PATTERN (NEXT_INSN (p))), 0))
		       == SET_DEST (PATTERN (p)))
		   && !reg_mentioned_p (SET_DEST (PATTERN (p)),
					SET_SRC (PATTERN (NEXT_INSN (p)))))
	    {
	      register int regno = REGNO (SET_DEST (PATTERN (p)));
	      if (n_times_set[regno] == 2)
		{
		  register struct movable *m;
		  int count;
		  m = (struct movable *) alloca (sizeof (struct movable));
		  m->next = 0;
		  m->insn = p;
		  m->force = 0;
		  m->consec = 0;
		  m->done = 0;
		  m->forces = 0;
		  m->partial = 1;
		  m->regno = regno;
		  m->cond = 0;
		  /* Say "global" so this register is not combined
		     with any other.  In fact, it is sometimes possible
		     to combine two of these registers, but the criteria
		     are special and have not been programmed in.  */
		  m->global = 1;
		  m->match = 0;
		  m->lifetime = (uid_luid[regno_last_uid[regno]]
				 - uid_luid[regno_first_uid[regno]]);
		  m->savings = 1;
		  n_times_set[regno] = -1;
		  /* Add M to the end of the chain MOVABLES.  */
		  if (movables == 0)
		    movables = m;
		  else
		    last_movable->next = m;
		  last_movable = m;
		  /* Skip the consecutive insns, if there are any.  */
		  for (count = m->consec - 1; count >= 0; count--)
		    {
		      /* If first insn of libcall sequence, skip to end.  */
		      /* Do this at start of loop, since p is guaranteed to 
			 be an insn here.  */
		      if (temp = find_reg_note (p, REG_LIBCALL, 0))
			{
			  p = XEXP (temp, 0);
			  /* Count the libcall as ten insns in terms of
			     importance of moving it.  */
			  m->savings += 10;
			}
		      
		      do p = NEXT_INSN (p);
		      while (GET_CODE (p) == NOTE);
		    }
		}
	    }
	}
      /* Past a call insn, we get to insns which might not be executed
	 because the call might exit.  This matters for insns that trap.  */
      else if (GET_CODE (p) == CALL_INSN)
	call_passed = 1;
      /* Past a label or a jump, we get to insns for which we
	 can't count on whether or how many times they will be
	 executed during each iteration.  Therefore, we can
	 only move out sets of trivial variables
	 (those not used after the loop).  */
      else if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
	maybe_never = 1;
    }

  /* For each movable insn, see if the reg that it loads
     leads when it dies right into another conditionally movable insn.
     If so, record that the second insn "forces" the first one,
     since the second can be moved only if the first is.  */

  {
    register struct movable *m, *m1;
    for (m1 = movables; m1; m1 = m1->next)
      /* Omit this if moving just the (SET (REG) 0) of a zero-extend.  */
      if (!m1->partial)
	{
	  int regno = m1->regno;
	  for (m = m1->next; m; m = m->next)
	    /* ??? Could this be a bug?  What if CSE caused the
	       register of M1 to be used after this insn?
	       Since CSE does not update regno_last_uid,
	       this insn M->insn might not be where it dies.
	       But very likely this doesn't matter; what matters is
	       that M's reg is computed from M1's reg.  */
	    if (INSN_UID (m->insn) == regno_last_uid[regno])
	      break;
	  if (m != 0 && m->set_src == SET_DEST (PATTERN (m1->insn)))
	    m = 0;

	  /* Increase the priority of the moving the first insn
	     since it permits the second to be moved as well.  */
	  if (m != 0)
	    {
	      m->forces = m1;
	      m1->lifetime += m->lifetime;
	      m1->savings += m1->savings;
	    }
	}
  }

  /* See if there are multiple movable insns that load the same value.
     If there are, make all but the first point at the first one
     through the `match' field, and add the priorities of them
     all together as the priority of the first.  */

  {
    register struct movable *m;
    char *matched_regs = (char *) alloca (nregs);

    /* Regs that are set more than once are not allowed to match
       or be matched.  I'm no longer sure why not.  */
    /* Perhaps testing m->consec_sets would be more appropriate here?  */

    for (m = movables; m; m = m->next)
      if (m->match == 0 && n_times_used[m->regno] == 1)
	{
	  register struct movable *m1;
	  int regno = m->regno;

	  bzero (matched_regs, nregs);
	  matched_regs[regno] = 1;

	  for (m1 = m->next; m1; m1 = m1->next)
	    if (m1->match == 0 && n_times_used[m1->regno] == 1
		/* A reg used outside the loop mustn't be eliminated.  */
		&& !m1->global
		&& (matched_regs[m1->regno]
		    ||
		    (
		     /* Can't combine regs with different modes
			even if loaded from the same constant.  */
		     (GET_MODE (SET_DEST (PATTERN (m->insn)))
		      == GET_MODE (SET_DEST (PATTERN (m1->insn))))
		     /* See if the source of M1 says it matches M.  */
		     && ((GET_CODE (m1->set_src) == REG
			  && matched_regs[REGNO (m1->set_src)])
			 || rtx_equal_p (m->set_src, m1->set_src)
			 || (REG_NOTES (m->insn) && REG_NOTES (m1->insn)
			     && REG_NOTE_KIND (REG_NOTES (m->insn)) == REG_EQUIV
			     && REG_NOTE_KIND (REG_NOTES (m1->insn)) == REG_EQUIV
			     && rtx_equal_p (XEXP (REG_NOTES (m->insn), 0),
					     XEXP (REG_NOTES (m1->insn), 0)))))))
	      {
		m->lifetime += m1->lifetime;
		m->savings += m1->savings;
		m1->match = m;
		matched_regs[m1->regno] = 1;
	      }
	}
  }
	
  /* Now consider each movable insn to decide whether it is worth moving.
     Store 0 in n_times_set for each reg that is moved.  */

  move_movables (movables, threshold,
		 insn_count, loop_start, end, nregs);

  /* Now candidates that still have -1 are those not moved.
     Change n_times_set to indicate that those are not actually invariant.  */
  for (i = 0; i < nregs; i++)
    if (n_times_set[i] < 0)
      n_times_set[i] = n_times_used[i];

  if (flag_strength_reduce)
    strength_reduce (scan_start, end, loop_top,
		     insn_count, loop_start, end, nregs);
}

/* Scan MOVABLES, and move the insns that deserve to be moved.
   If two matching movables are combined, replace one reg with the
   other throughout.  */

static void
move_movables (movables, threshold, insn_count, loop_start, end, nregs)
     struct movable *movables;
     int threshold;
     int insn_count;
     rtx loop_start;
     rtx end;
     int nregs;
{
  rtx new_start = 0;
  register struct movable *m;
  register rtx p;
  /* Map of pseudo-register replacements to handle combining
     when we move several insns that load the same value
     into different pseudo-registers.  */
  rtx *reg_map = (rtx *) alloca (nregs * sizeof (rtx));
  char *already_moved = (char *) alloca (nregs);

  bzero (already_moved, nregs);
  bzero (reg_map, nregs * sizeof (rtx));

  num_movables = 0;

  for (m = movables; m; m = m->next)
    {
      /* Describe this movable insn.  */

      if (loop_dump_stream)
	{
	  fprintf (loop_dump_stream, "Insn %d: regno %d (life %d), ",
		   INSN_UID (m->insn), m->regno, m->lifetime);
	  if (m->consec > 0)
	    fprintf (loop_dump_stream, "consec %d, ", m->consec);
	  if (m->cond)
	    fprintf (loop_dump_stream, "cond ");
	  if (m->force)
	    fprintf (loop_dump_stream, "force ");
	  if (m->global)
	    fprintf (loop_dump_stream, "global ");
	  if (m->done)
	    fprintf (loop_dump_stream, "done ");
	  if (m->match)
	    fprintf (loop_dump_stream, "matches %d ",
		     INSN_UID (m->match->insn));
	  if (m->forces)
	    fprintf (loop_dump_stream, "forces %d ",
		     INSN_UID (m->forces->insn));
	}

      /* Count movables.  Value used in heuristics in strength_reduce.  */
      num_movables++;

      /* Ignore the insn if it's already done (it matched something else).
	 Otherwise, see if it is now safe to move.  */

      if (!m->done
	  && (! m->cond
	      || (1 == invariant_p (m->set_src)
		  && (m->consec == 0
		      || 1 == consec_sets_invariant_p (SET_DEST (PATTERN (m->insn)),
						       m->consec + 1,
						       m->insn))))
	  && (! m->forces || m->forces->done))
	{
	  register int regno;
	  register rtx p;
	  int savings = m->savings;

	  /* We have an insn that is safe to move.
	     Compute its desirability.  */

	  p = m->insn;
	  regno = m->regno;

	  if (loop_dump_stream)
	    fprintf (loop_dump_stream, "savings %d ", savings);

	  /* An insn MUST be moved if we already moved something else
	     which is safe only if this one is moved too: that is,
	     if already_moved[REGNO] is nonzero.  */

	  /* An insn is desirable to move if the new lifetime of the
	     register is no more than THRESHOLD times the old lifetime.
	     If it's not desirable, it means the loop is so big
	     that moving won't speed things up much,
	     and it is liable to make register usage worse.  */

	  /* It is also desirable to move if it can be moved at no
	     extra cost because something else was already moved.  */

	  if (already_moved[regno]
	      || (threshold * savings * m->lifetime) >= insn_count
	      || (m->forces && m->forces->done
		  && n_times_used[m->forces->regno] == 1))
	    {
	      int count;
	      register struct movable *m1;
	      rtx first;

	      for (count = m->consec; count >= 0; count--)
		{
		  rtx i1, temp;

		  /* If first insn of gnulib call sequence, skip to end.  */
		  /* Do this at start of loop, since p is guaranteed to 
		     be an insn here.  */
		  if (temp = find_reg_note (p, REG_LIBCALL, 0))
		    p = XEXP (temp, 0);
		  
		  /* If last insn of gnulib call sequence, move all
		     insns except the last before the loop.  The last insn is
		     handled in the normal manner.  */
		  if (temp = find_reg_note (p, REG_RETVAL, 0))
		    {
		      rtx fn_address = 0;
		      rtx fn_reg = 0;
		      first = 0;
		      for (temp = XEXP (temp, 0); temp != p;
			   temp = NEXT_INSN (temp))
			{
			  rtx body = PATTERN (temp);
			  rtx n;
			  /* Extract the function address from the insn
			     that loads it into a register.
			     If this insn was cse'd, we get incorrect code.
			     So delete it and stick the fn address right
			     into the call insn.  Since the moved insns
			     won't be cse'd, that does no harm.  */
			  if (GET_CODE (NEXT_INSN (temp)) == CALL_INSN
			      && GET_CODE (body) == SET
			      && GET_CODE (SET_DEST (body)) == REG
			      && (n = find_reg_note (temp, REG_EQUIV, 0)))
			    {
			      fn_reg = SET_SRC (body);
			      if (GET_CODE (fn_reg) != REG)
				fn_reg = SET_DEST (body);
			      fn_address = XEXP (n, 0);
			      continue;
			    }
			  /* We have the call insn.
			     Substitute the fn address for the reg
			     that we believe this insn will use.  */
			  if (GET_CODE (temp) == CALL_INSN
			      && fn_address != 0)
			    replace_call_address (body, fn_reg, fn_address);
			  if (GET_CODE (temp) == CALL_INSN)
			    i1 = emit_call_insn_before (body, loop_start);
			  else
			    i1 = emit_insn_before (body, loop_start);
			  if (first == 0)
			    first = i1;
			  REG_NOTES (i1) = REG_NOTES (temp);
			  delete_insn (temp);
			}
		    }
		  if (GET_CODE (PATTERN (p)) == CALL_INSN)
		    i1 = emit_call_insn_before (PATTERN (p), loop_start);
		  else
		    i1 = emit_insn_before (PATTERN (p), loop_start);

		  if (new_start == 0)
		    new_start = i1;

		  if (loop_dump_stream)
		    fprintf (loop_dump_stream, "moved to %d", INSN_UID (i1));

		  /* Mark the moved, invariant reg as being equivalent to
		     its constant value.  */
		  REG_NOTES (i1) = REG_NOTES (p);
		  if (REG_NOTES (i1) == 0
		      && ! m->partial /* But not if it's a zero-extend clr. */
		      && ! m->global /* and not if used outside the loop
					(since it might get set outside).  */
		      && CONSTANT_P (SET_SRC (PATTERN (p))))
		    REG_NOTES (i1)
		      = gen_rtx (EXPR_LIST, REG_EQUIV,
				 SET_SRC (PATTERN (p)), REG_NOTES (i1));

		  /* If library call, now fix the REG_NOTES that contain
		     insn pointers, namely REG_LIBCALL on FIRST
		     and REG_RETVAL on I1.  */
		  if (temp = find_reg_note (i1, REG_RETVAL, 0))
		    {
		      XEXP (temp, 0) = first;
		      temp = find_reg_note (first, REG_LIBCALL, 0);
		      XEXP (temp, 0) = i1;
		    }

		  delete_insn (p);
		  do p = NEXT_INSN (p);
		  while (GET_CODE (p) == NOTE);
		}

	      /* The more regs we move, the less we like moving them.  */
	      threshold -= 3;

	      /* Any other movable that loads the same register
		 MUST be moved.  */
	      already_moved[regno] = 1;

	      /* The reg set here is now invariant.  */
	      if (! m->partial)
		n_times_set[regno] = 0;

	      m->done = 1;

	      /* Change the length-of-life info for the register
		 to say it lives at least the full length of this loop.
		 This will help guide optimizations in outer loops.  */

	      if (uid_luid[regno_first_uid[regno]] > INSN_LUID (loop_start))
		/* This is the old insn before all the moved insns.
		   We can't use the moved insn because it is out of range
		   in uid_luid.  Only the old insns have luids.  */
		regno_first_uid[regno] = INSN_UID (loop_start);
	      if (uid_luid[regno_last_uid[regno]] < INSN_LUID (end))
		regno_last_uid[regno] = INSN_UID (end);

	      /* Combine with this moved insn any other matching movables.  */

	      for (m1 = m->next; m1; m1 = m1->next)
		if (m1->match == m)
		  {
		    rtx temp;

		    /* Schedule the reg loaded by M1
		       for replacement so that shares the reg of M.  */
		    reg_map[m1->regno] = SET_DEST (PATTERN (m->insn));
		    /* Get rid of the matching insn
		       and prevent further processing of it.  */
		    m1->done = 1;

		    /* if library call, delete all insn except last, which
		       is deleted below */
		    if (temp = find_reg_note (m1->insn, REG_RETVAL, 0))
		      {
			for (temp = XEXP (temp, 0); temp != m1->insn;
			     temp = NEXT_INSN (temp))
			    delete_insn (temp);
		      }
		    delete_insn (m1->insn);

		    /* Any other movable that loads the same register
		       MUST be moved.  */
		    already_moved[m1->regno] = 1;

		    /* The reg merged here is now invariant.  */
		    if (m->partial)
		      n_times_set[m1->regno] = 0;
		  }
	    }
	  else if (loop_dump_stream)
	    fprintf (loop_dump_stream, "not desirable");
	}
      else if (loop_dump_stream && !m->match)
	fprintf (loop_dump_stream, "not safe");

      if (loop_dump_stream)
	fprintf (loop_dump_stream, "\n");
    }

  if (new_start == 0)
    new_start = loop_start;

  /* Go through all the instructions in the loop, making
     all the register substitutions scheduled in REG_MAP.  */
  for (p = new_start; p != end; p = NEXT_INSN (p))
    if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
	|| GET_CODE (p) == CALL_INSN)
      replace_regs (PATTERN (p), reg_map, nregs);
}

/* Optionally change a loop which enters just before the endtest
   to one which falls straight in
   after skipping around the entire loop if the endtest would drop out.
   Returns 1 if the change was made, 0 if the loop was not really suitable.  */

int
loop_skip_over (start, end, loop_entry_jump)
     rtx start;
     rtx end;
     rtx loop_entry_jump;
{
  rtx endtestjump;
  register rtx p = JUMP_LABEL (loop_entry_jump);

  while (GET_CODE (p) != INSN && GET_CODE (p) != JUMP_INSN
	 && GET_CODE (p) != CALL_INSN)
    p = NEXT_INSN (p);
  endtestjump = next_real_insn (p);

  /* Check that we (1) enter at a compare insn and (2)
     the insn (presumably a jump) following that compare
     is the last in the loop and jumps back to the loop beginning.  */

  if (sets_cc0_p (PATTERN (p)) > 0
      && endtestjump == prev_real_insn (end)
      && prev_real_insn (JUMP_LABEL (endtestjump)) == loop_entry_jump)
    {
      rtx newlab;
      /* This is the jump that we insert.  */
      rtx new_jump;

      /* Ok, duplicate that test before start of loop.  */
      emit_insn_before (copy_rtx (PATTERN (p)), start);
      /* Make a new entry-jump (before the original one)
	 whose condition is opposite to the loop-around endtest
	 and which jumps around the loop (to just after the ending NOTE).  */
      newlab = gen_label_rtx ();
      emit_label_after (newlab, end);
      emit_jump_insn_before (copy_rtx (PATTERN (endtestjump)), start);
      new_jump = PREV_INSN (start);
      JUMP_LABEL (new_jump) = JUMP_LABEL (endtestjump);
      LABEL_NUSES (JUMP_LABEL (endtestjump))++;
      invert_jump (new_jump, newlab);
      /* Delete the original entry-jump.  */
      delete_insn (loop_entry_jump);

      return 1;
    }

  return 0;
}

/* Throughout the rtx X, replace many registers according to REG_MAP.
   Return the replacement for X (which may be X with altered contents).
   REG_MAP[R] is the replacement for register R, or 0 for don't replace.
   NREGS is the length of REG_MAP; regs >= NREGS are not mapped.  */

static rtx
replace_regs (x, reg_map, nregs)
     rtx x;
     rtx *reg_map;
     int nregs;
{
  register RTX_CODE code = GET_CODE (x);
  register int i;
  register char *fmt;

  switch (code)
    {
    case PC:
    case CC0:
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case LABEL_REF:
      return x;

    case REG:
      /* Verify that the register has an entry before trying to access it.  */
      if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0)
	return reg_map[REGNO (x)];
      return x;
    }

  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    {
      if (fmt[i] == 'e')
	XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs);
      if (fmt[i] == 'E')
	{
	  register int j;
	  for (j = 0; j < XVECLEN (x, i); j++)
	    XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map, nregs);
	}
    }
  return x;
}

/* Scan X and replace the address of any MEM in it with ADDR.
   REG is the address that MEM should have before the replacement.  */

static void
replace_call_address (x, reg, addr)
     rtx x, reg, addr;
{
  register RTX_CODE code = GET_CODE (x);
  register int i;
  register char *fmt;

  switch (code)
    {
    case PC:
    case CC0:
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case LABEL_REF:
    case REG:
      return;

    case SET:
      /* Short cut for very common case.  */
      replace_call_address (XEXP (x, 1), reg, addr);
      return;

    case CALL:
      /* Short cut for very common case.  */
      replace_call_address (XEXP (x, 0), reg, addr);
      return;

    case MEM:
      /* If this MEM uses a reg other than the one we expected,
	 something is wrong.  */
      if (XEXP (x, 0) != reg)
	abort ();
      XEXP (x, 0) = addr;
      return;
    }

  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    {
      if (fmt[i] == 'e')
	replace_call_address (XEXP (x, i), reg, addr);
      if (fmt[i] == 'E')
	{
	  register int j;
	  for (j = 0; j < XVECLEN (x, i); j++)
	    replace_call_address (XVECEXP (x, i, j), reg, addr);
	}
    }
}

#if 0
/* P is an instruction that sets a register to the result of a ZERO_EXTEND.
   Replace it with an instruction to load just the low bytes
   if the machine supports such an instruction,
   and insert above LOOP_START an instruction to clear the register.  */

static void
constant_high_bytes (p, loop_start)
     rtx p, loop_start;
{
  register rtx new;
  register int insn_code_number;

  /* Try to change (SET (REG ...) (ZERO_EXTEND (..:B ...)))
     to (SET (STRICT_LOW_PART (SUBREG:B (REG...))) ...).  */

  new = gen_rtx (SET, VOIDmode,
		 gen_rtx (STRICT_LOW_PART, VOIDmode,
			  gen_rtx (SUBREG, GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)),
				   SET_DEST (PATTERN (p)),
				   0)),
		 XEXP (SET_SRC (PATTERN (p)), 0));
  insn_code_number = recog (new, p);

  if (insn_code_number)
    {
      register int i;

      /* Clear destination register before the loop.  */
      emit_insn_before (gen_rtx (SET, VOIDmode,
				 SET_DEST (PATTERN (p)),
				 const0_rtx),
			loop_start);

      /* Inside the loop, just load the low part.  */
      PATTERN (p) = new;
    }
}
#endif

/* Verify that the ostensible loop starting at START
   really is a loop: nothing jumps into it from outside.
   Return the marker for the end of the loop, or zero if not a real loop.

   Also set the variables `unknown_*_altered' and `loop_has_call',
   and fill in the array `loop_store_addrs'.  */

static rtx
verify_loop (f, start)
     rtx f, start;
{
  register int level = 1;
  register rtx insn, end;

  /* First find the LOOP_END that matches.
     Also check each insn for storing in memory and record where.  */

  unknown_address_altered = 0;
  unknown_aggregate_altered = 0;
  fixed_aggregate_altered = 0;
  loop_has_call = 0;
  loop_store_addrs_idx = 0;

  num_mem_sets = 0;
  loops_enclosed = 1;

  for (insn = NEXT_INSN (start); level > 0; insn = NEXT_INSN (insn))
    {
      if (insn == 0)
	/* Parse errors can cause a loop-beg with no loop-end.  */
	return 0;
      if (GET_CODE (insn) == NOTE)
	{
	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
	    {
	      ++level;
	      /* Count number of loops contained in this one.  */
	      loops_enclosed++;
	    }
	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
	    {
	      --level;
	      if (level == 0)
		{
		  end = insn;
		  break;
		}
	    }
	}
      else if (GET_CODE (insn) == CALL_INSN)
	{
	  unknown_address_altered = 1;
	  loop_has_call = 1;
	}
/* ???
      else if (! unknown_address_altered) */
      else
	{
	  if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
	    note_stores (PATTERN (insn), note_addr_stored);
	}
    }

  /* Now scan all jumps in the function and see if any of them can
     reach a label within the range of the loop.  */

  for (insn = f; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == JUMP_INSN
	/* Don't get fooled by jumps inserted by loop-optimize.
	   They don't have valid LUIDs, and they never jump into loops.  */
	&& INSN_UID (insn) < max_uid
	&& (INSN_LUID (insn) < INSN_LUID (start)
	    || INSN_LUID (insn) > INSN_LUID (end))
	/* We have a jump that is outside the loop.
	   Does it jump into the loop?  */
	&& can_jump_into_range_p (PATTERN (insn),
				  INSN_LUID (start), INSN_LUID (end)))
      return 0;

#if 0      
  /* Now scan all labels between them and check for any jumps from outside.
     This uses the ref-chains set up by find_basic_blocks.
     This code is not used because it's more convenient for other reasons
     to do the loop optimization before find_basic_blocks.  */

  for (insn = start; insn != end; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == CODE_LABEL)
      {
	register rtx y;
	for (y = LABEL_REFS (insn); y != insn; y = LABEL_NEXTREF (y))
	  if (INSN_LUID (CONTAINING_INSN (y)) < INSN_LUID (start)
	      || INSN_LUID (CONTAINING_INSN (y)) > INSN_LUID (end))
	    return 0;
      }
#endif

  return end;
}

/* Return 1 if somewhere in X is a LABEL_REF to a label
   located between BEG and END.  */

static int
can_jump_into_range_p (x, beg, end)
     rtx x;
     int beg, end;
{
  register RTX_CODE code = GET_CODE (x);
  register int i;
  register char *fmt;

  if (code == LABEL_REF)
    {
      register int luid = INSN_LUID (XEXP (x, 0));
      return luid > beg && luid < end;
    }

  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    {
      if (fmt[i] == 'e')
	{
	  if (can_jump_into_range_p (XEXP (x, i), beg, end))
	    return 1;
	}
      else if (fmt[i] == 'E')
	{
	  register int j;
	  for (j = 0; j < XVECLEN (x, i); j++)
	    if (can_jump_into_range_p (XVECEXP (x, i, j), beg, end))
	      return 1;
	}
    }

  return 0;
}

/* Record that a memory reference X is being set.  */

static void
note_addr_stored (x)
     rtx x;
{
  if (x == 0 || GET_CODE (x) != MEM)
    return;

  /* Count number of memory writes.
     This affects heuristics in strength_reduce.  */
  num_mem_sets++;
  if (unknown_address_altered)
    return;

  if (GET_MODE (x) == BLKmode)
    unknown_address_altered = 1;
  else if (rtx_addr_varies_p (x))
    {
      if (GET_CODE (XEXP (x, 0)) == PLUS)
	unknown_aggregate_altered = 1;
      else
	unknown_address_altered = 1;
    }
  else
    {
      register int i;
      register rtx addr = XEXP (x, 0);

      if (MEM_IN_STRUCT_P (x))
	fixed_aggregate_altered = 1;
      for (i = 0; i < loop_store_addrs_idx; i++)
	if (rtx_equal_p (loop_store_addrs[i], addr))
	  {
	    if (loop_store_widths[i] < GET_MODE_SIZE (GET_MODE (x)))
	      loop_store_widths[i] = GET_MODE_SIZE (GET_MODE (x));
	    break;
	  }
      if (i == NUM_STORES)
	unknown_address_altered = 1;
      else if (i == loop_store_addrs_idx)
	{
	  loop_store_widths[i] = GET_MODE_SIZE (GET_MODE (x));
	  loop_store_addrs[loop_store_addrs_idx++] = addr;
	}
    }
}

/* Return nonzero if the rtx X is invariant over the current loop.

   The value is 2 if we refer to something only conditionally invariant.

   If `unknown_address_altered' is nonzero, no memory ref is invariant.
   Otherwise if `unknown_aggregate_altered' is nonzero,
   a memory ref is invariant if it is not part of an aggregate
   and its address is fixed and not in `loop_store_addrs'.
   Otherwise if `fixed_aggregate_altered' is nonzero,
   a memory ref is invariant
   if its address is fixed and not in `loop_store_addrs'.
   Otherwise, a memory ref is invariant if its address is fixed and not in
   `loop_store_addrs' or if it is not an aggregate.  */

static int
invariant_p (x)
     register rtx x;
{
  register int i;
  register RTX_CODE code = GET_CODE (x);
  register char *fmt;
  int conditional = 0;

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case SYMBOL_REF:
    case LABEL_REF:
    case CONST:
      return 1;

    case PC:
    case CC0:
      return 0;

    case REG:
      /* We used to check RTX_UNCHANGING_P (x) here, but that is invalid
	 since the reg might be set by initialization within the loop.  */
      if (x == frame_pointer_rtx || x == arg_pointer_rtx)
	return 1;
      if (n_times_set[REGNO (x)] == -1)
	return 2;
      return n_times_set[REGNO (x)] == 0;

    case MEM:
      /* A store in a varying-address scalar (or a subroutine call)
	 could clobber anything in memory.  */
      if (unknown_address_altered)
	return 0;
      /* Don't mess with volatile memory references.  */
      if (MEM_VOLATILE_P (x))
	return 0;
#if 0
      /* If it's declared read-only, it is invariant
	 if its address is invariant.  */
      if (RTX_UNCHANGING_P (x))
	return invariant_p (XEXP (x, 0));
#endif
      /* A store in a varying-address aggregate component
	 could clobber anything except a scalar with a fixed address.  */
      if (unknown_aggregate_altered
	  && ((MEM_IN_STRUCT_P (x) || GET_CODE (XEXP (x, 0)) == PLUS)
	      || rtx_addr_varies_p (x)))
	return 0;
      /* A store in a fixed-address aggregate component
	 could clobber anything whose address is not fixed,
	 even an aggregate component.  */
      if (fixed_aggregate_altered
	  && rtx_addr_varies_p (x))
	return 0;
      /* Any store could clobber a varying-address scalar.  */
      if (loop_store_addrs_idx
	  && !(MEM_IN_STRUCT_P (x) || GET_CODE (XEXP (x, 0)) == PLUS)
	  && rtx_addr_varies_p (x))
	return 0;
      /* A store in a fixed address clobbers overlapping references.  */
      for (i = loop_store_addrs_idx - 1; i >= 0; i--)
	if (addr_overlap_p (x, loop_store_addrs[i], loop_store_widths[i]))
	  return 0;
      /* It's not invalidated by a store in memory
	 but we must still verify the address is invariant.  */
      break;

    case ASM_OPERANDS:
      /* Don't mess with insns declared volatile.  */
      if (MEM_VOLATILE_P (x))
	return 0;
    }

  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    {
      if (fmt[i] == 'e')
	{
	  int tem = invariant_p (XEXP (x, i));
	  if (tem == 0)
	    return 0;
	  if (tem == 2)
	    conditional = 1;
	}
      else if (fmt[i] == 'E')
	{
	  register int j;
	  for (j = 0; j < XVECLEN (x, i); j++)
	    {
	      int tem = invariant_p (XVECEXP (x, i, j));
	      if (tem == 0)
		return 0;
	      if (tem == 2)
		conditional = 1;
	    }

	}
    }

  return 1 + conditional;
}

/* Return 1 if OTHER (a mem ref) overlaps the area of memory
   which is SIZE bytes starting at BASE.  */

int
addr_overlap_p (other, base, size)
     rtx other;
     rtx base;
     int size;
{
  int start = 0, end;

  if (GET_CODE (base) == CONST)
    base = XEXP (base, 0);
  if (GET_CODE (base) == PLUS
      && GET_CODE (XEXP (base, 1)) == CONST_INT)
    {
      start = INTVAL (XEXP (base, 1));
      base = XEXP (base, 0);
    }

  end = start + size;
  return refers_to_mem_p (other, base, start, end);
}

/* Return nonzero if all the insns in the loop that set REG
   are INSN and the immediately following insns,
   and if each of those insns sets REG in an invariant way
   (not counting uses of REG in them).

   The value is 2 if some of these insns are only conditionally invariant.

   We assume that INSN itself is the first set of REG
   and that its source is invariant.  */

static int
consec_sets_invariant_p (reg, n_sets, insn)
     int n_sets;
     rtx reg, insn;
{
  register rtx p = insn;
  register int regno = REGNO (reg);
  rtx temp;
  /* Number of sets we have to insist on finding after INSN.  */
  int count = n_sets - 1;
  int old = n_times_set[regno];
  int tem = 0;

  /* If N_SETS hit the limit, we can't rely on its value.  */
  if (n_sets == 127)
    return 0;

  n_times_set[regno] = 0;

  while (count > 0)
    {
      register enum rtx_code code;
      p = NEXT_INSN (p);
      code = GET_CODE (p);

      /* If library call, skip to end of of it.  */
      if (code == INSN && (temp = find_reg_note (p, REG_LIBCALL, 0)))
	p = XEXP (temp, 0);

      if (code == INSN && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG
	  && REGNO (SET_DEST (PATTERN (p))) == regno
	  && (tem |= invariant_p (SET_SRC (PATTERN (p)))
	      || ((temp = find_reg_note (p, REG_EQUAL, 0))
		  && (tem |= invariant_p (XEXP (temp, 0))))))
	count--;
      else if (code != NOTE)
	{
	  n_times_set[regno] = old;
	  return 0;
	}
    }

  n_times_set[regno] = old;
  /* If invariant_p ever returned 2, we return 2.  */
  return 1 + (tem & 2);
}

#if 0
/* I don't think this condition is sufficient to allow INSN
   to be moved, so we no longer test it.  */

/* Return 1 if all insns in the basic block of INSN and following INSN
   that set REG are invariant according to TABLE.  */

static int
all_sets_invariant_p (reg, insn, table)
     rtx reg, insn;
     short *table;
{
  register rtx p = insn;
  register int regno = REGNO (reg);

  while (1)
    {
      register enum rtx_code code;
      p = NEXT_INSN (p);
      code = GET_CODE (p);
      if (code == CODE_LABEL || code == JUMP_INSN)
	return 1;
      if (code == INSN && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG
	  && REGNO (SET_DEST (PATTERN (p))) == regno)
	{
	  if (!invariant_p (SET_SRC (PATTERN (p)), table))
	    return 0;
	}
    }
}
#endif /* 0 */

/* Increment N_TIMES_SET at the index of each register
   that is modified by an insn between FROM and TO.
   If the value of an element of N_TIMES_SET becomes 127 or more,
   stop incrementing it, to avoid overflow.

   Store in *COUNT_PTR the number of actual instruction
   in the loop.  We use this to decide what is worth moving out.  */

/* last_set[n] is nonzero iff reg n has been set in the current basic block.
   In that case, it is the insn that last set reg n.  */

static void
count_loop_regs_set (from, to, may_not_move, count_ptr, nregs)
     register rtx from, to;
     char *may_not_move;
     int *count_ptr;
     int nregs;
{
  register rtx *last_set = (rtx *) alloca (nregs * sizeof (rtx));
  register rtx insn;
  register int count = 0;
  register rtx dest;

  bzero (last_set, nregs * sizeof (rtx));
  for (insn = from; insn != to; insn = NEXT_INSN (insn))
    {
      if (GET_CODE (insn) == CALL_INSN)
	{
	  /* If a register is used as a subroutine address,
	     don't allow this register's setting to be moved out of the loop.
	     This condition is not at all logically correct
	     but it averts a very common lossage pattern
	     and creates lossage much less often.  */
	  if (GET_CODE (PATTERN (insn)) == CALL
	      && GET_CODE (XEXP (PATTERN (insn), 0)) == MEM
	      && GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == REG)
	    {
	      register int regno
		= REGNO (XEXP (XEXP (PATTERN (insn), 0), 0));
	      may_not_move[regno] = 1;
	    }
	  else if (GET_CODE (PATTERN (insn)) == SET
	      && GET_CODE (SET_SRC (PATTERN (insn))) == CALL
	      && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 0)) == MEM
	      && GET_CODE (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0)) == REG)
	    {
	      register int regno
		= REGNO (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0));
	      may_not_move[regno] = 1;
	      /* The call insn itself sets a reg, which cannot be moved.  */
	      may_not_move[REGNO (SET_DEST (PATTERN (insn)))] = 1;
	      if (n_times_set[REGNO (SET_DEST (PATTERN (insn)))] < 127)
		n_times_set[REGNO (SET_DEST (PATTERN (insn)))]++;
	    }
	}
      if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN) 
	{
	  ++count;
	  if (GET_CODE (PATTERN (insn)) == CLOBBER
	      && GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
	    /* Don't move a reg that has an explicit clobber.
	       We might do so sometimes, but it's not worth the pain.  */
	    may_not_move[REGNO (XEXP (PATTERN (insn), 0))] = 1;
	  else if (GET_CODE (PATTERN (insn)) == SET)
	    {
	      dest = SET_DEST (PATTERN (insn));
	      while (GET_CODE (dest) == SUBREG
		     || GET_CODE (dest) == ZERO_EXTRACT
		     || GET_CODE (dest) == SIGN_EXTRACT
		     || GET_CODE (dest) == STRICT_LOW_PART)
		dest = XEXP (dest, 0);
	      if (GET_CODE (dest) == REG)
		{
		  register int regno = REGNO (dest);
		  /* If this is the first setting of this reg
		     in current basic block, and it was set before,
		     it must be set in two basic blocks, so it cannot
		     be moved out of the loop.  */
		  if (n_times_set[regno] > 0 && last_set[regno] == 0)
		    may_not_move[regno] = 1;
		  /* If this is not first setting in current basic block,
		     see if reg was used in between previous one and this.
		     If so, neither one can be moved.  */
		  if (last_set[regno] != 0
		      && reg_used_between_p (dest, last_set[regno], insn))
		    may_not_move[regno] = 1;
		  if (n_times_set[regno] < 127)
		    ++n_times_set[regno];
		  last_set[regno] = insn;
		}
	    }
	  else if (GET_CODE (PATTERN (insn)) == PARALLEL)
	    {
	      register int i;
	      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
		{
		  register rtx x = XVECEXP (PATTERN (insn), 0, i);
		  if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
		    /* Don't move a reg that has an explicit clobber.
		       It's not worth the pain to try to do it correctly.  */
		    may_not_move[REGNO (XEXP (x, 0))] = 1;
		  if (GET_CODE (x) == SET)
		    {
		      dest = SET_DEST (x);
		      while (GET_CODE (dest) == SUBREG
			     || GET_CODE (dest) == ZERO_EXTRACT
			     || GET_CODE (dest) == SIGN_EXTRACT
			     || GET_CODE (dest) == STRICT_LOW_PART)
			dest = XEXP (dest, 0);
		      if (GET_CODE (dest) == REG)
			{
			  register int regno = REGNO (dest);
			  if (n_times_set[regno] < 127)
			    ++n_times_set[regno];
			  may_not_move[regno] = 1;
			  last_set[regno] = insn;
			}
		    }
		}
	    }
	}
      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
	bzero (last_set, nregs * sizeof (rtx));
    }
  *count_ptr = count;
}

/* Given a loop that is bounded by LOOP_START and LOOP_END
   and that is entered at SCAN_START,
   return 1 if the register set by insn INSN is used by
   any insn that precedes INSN in cyclic order starting
   from the loop entry point.  */

static int
loop_reg_used_before_p (insn, loop_start, scan_start, loop_end)
     rtx insn, loop_start, scan_start, loop_end;
{
  rtx reg = SET_DEST (PATTERN (insn));
  if (INSN_LUID (scan_start) > INSN_LUID (insn))
    return (reg_used_between_p (reg, scan_start, loop_end)
	    || reg_used_between_p (reg, loop_start, insn));
  else
    return reg_used_between_p (reg, scan_start, insn);
}

/* Return nonzero if evaluating rtx X might cause a trap.  */

static int
may_trap_p (x)
     rtx x;
{
  int i;
  enum rtx_code code = GET_CODE (x);
  char *fmt;

  switch (code)
    {
      /* Handle these cases fast.  */
    case CONST_INT:
    case CONST_DOUBLE:
    case SYMBOL_REF:
    case LABEL_REF:
    case CONST:
    case PC:
    case CC0:
    case REG:
      return 0;

      /* Memory ref can trap unless it's a static var or a stack slot.  */
    case MEM:
      return rtx_varies_p (XEXP (x, 0));

      /* Division by a non-constant might trap.  */
    case DIV:
    case MOD:
    case UDIV:
    case UMOD:
      if (! CONSTANT_P (XEXP (x, 1))
	  && GET_CODE (XEXP (x, 1)) != CONST_DOUBLE)
	return 1;
    default:
      /* Any floating arithmetic may trap.  */
      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
	return 1;
    }

  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    {
      if (fmt[i] == 'e')
	{
	  if (may_trap_p (XEXP (x, i)))
	    return 1;
	}
      else if (fmt[i] == 'E')
	{
	  register int j;
	  for (j = 0; j < XVECLEN (x, i); j++)
	    if (may_trap_p (XVECEXP (x, i, j)))
	      return 1;
	}
    }
  return 0;
}

/* A "basic induction variable" or biv is a pseudo reg that is set
   (within this loop) only by incrementing or decrementing it.  */
/* A "general induction variable" or giv is a pseudo reg whose
   value is a linear function of a biv.  */

/* Bivs are recognized by `basic_induction_var';
   Givs by `general_induct_var'.  */

/* An enum for the two different types of givs, those that are used
   as memory addresses and those that are calculated into registers.  */
enum g_types { DEST_ADDR, DEST_REG };

/* A `struct induction' is created for every instruction that sets
   an induction variable (either a biv or a giv).  */

struct induction
{
  rtx insn;		       /* The insn that sets a biv or giv */
  rtx new_reg;		       /* New register, containing strength reduced
				  version of this giv.  */
  int src_regno;	       /* Biv from which this giv is computed.
				  (If this is a biv, then this is the biv.)  */
  enum g_types giv_type;       /* Indicate whether DEST_ADDR or DEST_REG giv */
  int dest_regno;	       /* Destination register for insn: this is the
				  register which was the biv or giv.
				  For a biv, this equals src_reg.
				  For a DEST_ADDR type giv, this is 0.  */
  rtx *location;	       /* Place in the insn where this giv occurs.
				  If GIV_TYPE is DEST_REG, this is 0.  */
  rtx mult_val;		       /* Multiplicative factor for src_reg.  */
  rtx add_val;		       /* Additive constant for that product.  */
  int benefit;		       /* Gain from eliminating this insn.  */
  int consec;		       /* The number of consecutive insn that set this
				  register; they are all eliminated if this
				  one is.  */
  char replaceable;	       /* 1 if we can substitute the strength-reduced
				  variable for the original variable.
				  0 means they must be kept separate and the
				  new one must be copied into the old pseudo
				  reg each time the old one is set.  */
  char ignore;		       /* 1 prohibits further processing of this giv */
  int lifetime;		       /* Length of life of this giv */
  int times_used;	       /* # times this giv is used. */
  struct induction *family;    /* Links together all induction variables that
				  have the same src register.  */
  struct induction *forces;    /* Points to an induction variable insn which
				  is used only once, to compute this giv,
				  and hence can be deleted if this insn is
				  strength reduced.  */
  struct induction *forces2;   /* Likewise.  */
  struct induction *same;      /* Links together all induction variables that
				  have the same tuple (src, mult, add).  */
};

/* A `struct iv_class' is created for each biv.  */

struct iv_class {
  int regno;                   /* Pseudo reg which is the biv.  */
  int biv_count;               /* Number of insns setting this reg.  */
  struct induction *biv;       /* List of all insns that set this reg.  */
  int giv_count;               /* Number of givs computed from this biv.  */
  struct induction *giv;       /* List of all insns that compute a giv
				  from this reg.  */
  int total_benefit;           /* Sum of BENEFITs of all those givs */
  rtx initial_value;           /* Value of reg at loop start */
  struct iv_class *next;       /* Links all class structures together */
  char init_val_set;           /* Used during scan for initial value,
				  1 if assignment seen, 0 otherwise.  */
  char eliminable;	       /* 1 if plausible candidate for elimination.  */
  char nonneg;		       /* 1 if we added a REG_NONNEG note for this.  */
};

/* Definitions used by the basic induction variable discovery code.  */
enum iv_mode { UNKNOWN_INDUCT, BASIC_INDUCT, NOT_BASIC_INDUCT,
		 GENERAL_INDUCT };

/* Relative gain of eliminating various kinds of operations.  */
#define NO_BENEFIT    0
#define ADD_BENEFIT   1
#define SHIFT_BENEFIT 2
#define MULT_BENEFIT  4
#define LIBCALL_BENEFIT 15
/* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
   copy the value of the strength reduced giv to its original register.  */
#define COPY_PENALTY  2

/* Indexed by register number, indicates whether or not register is an
   induction variable, and if so what type.  */

static enum iv_mode *induct_var;

/* Indexed by register number, contains pointer to `struct induction'
   if register is a general induction variable.  */

static struct induction **induct_struct;

/* Indexed by register number, contains pointer to `struct iv_class'
   if register is a basic induction variable.  */

static struct iv_class **class_struct;

/*********************************/

/* ??? Unfinished optimizations, wilson@ji.Berkeley.EDU */

/* strength reduce addresses found in sources (set () (mem ())*/

/* There is one more optimization you might be interested in doing: to
   allocate pseudo registers for frequently-accessed memory locations.
   If the same memory location is referenced each time around, it might
   be possible to copy it into a register before and out after.
   This is especially useful when the memory location is a variable which
   is in a stack slot because somewhere its address is taken.  If the
   loop doesn't contain a function call and the variable isn't volatile,
   it is safe to keep the value in a register for the duration of the
   loop. One tricky thing is that the copying of the value back from the
   register has to be done on all exits from the loop.  You need to check that
   all the exits from the loop go to the same place. */

/* WARNING: the interaction of biv elimination, and recognizing 'constant'
   bivs may cause problems */

/* add heuristic so that DEST_ADDR strength reduction does not cause
   performance problems */

/* don't eliminate things that can be combined with an addressing mode?
   find all giv that have same biv and mult_val (now must also have
   same add_val), then for each giv, check to see if its only use
   dies in a following memory address, generate a new memory address
   and check to see if valid, if valid then store modified mem addr,
   else if not valid addr mark giv as not done so that it will get its
   own iv */

/* consec_sets_giv does not calculate replaceable and forces correctly,
   forces should be a more general linked list instead of two entries */

/* try to optimize branches when it is known that a biv is always positive */

/* when replace biv in compare insn, should replace with closest giv so that
   an optimized branch can still be recognized by combiner, i.e. VAXen acb */

/* should merge final_value calculation in check_dbra_loop with the 
   new final_biv_value function */

/* many of the checks involving uid_luid could be simplified if regscan
   was rerun in loop_optimize() whenever a register was added or moved,
   also some of the optimizations could be a little less conservative */

/* Perform strength reduction and induction variable elimination.  */

/* Pseudo registers created during this function will be beyond the last
   valid index in several tables including n_times_set and regno_last_uid.
   This does not cause a problem here, because the added registers cannot be
   givs outside of their loop, and hence will never be reconsidered.
   But scan_loop must check regnos to make sure they are in bounds.  */

static void
strength_reduce (scan_start, end, loop_top, insn_count,
		 loop_start, loop_end, nregs)
     rtx scan_start;
     rtx end;
     rtx loop_top;
     int insn_count;
     rtx loop_start;
     rtx loop_end;
     int nregs;
{
  rtx p;
  rtx inc_val;
  rtx mult_val;
  int dest_regno;
  int biv_found;
  /* This is 1 if current insn could be executed zero times in the loop.  */
  int maybe_never = 0;
  /* List of all possible basic induction variables.  */
  struct iv_class *iv_list = 0;
  /* Temporary list pointers for traversing iv_list.  */
  struct iv_class *bl, *backbl;
  /* Ratio of extra register life span we can justify
     for saving an instruction.  More if loop doesn't call subroutines
     since in that case saving an insn makes more difference
     and more registers are available.  */
  /* ??? could set this to last value of threshold in move_movables */
  int threshold = loop_has_call ? 17 : 34;
  /* Map of pseudo-register replacements.  */
  rtx *reg_map;

  induct_var = (enum iv_mode *) alloca (nregs * sizeof (induct_var[0]));
  bzero ((char *)induct_var, nregs * sizeof (induct_var[0]));
  induct_struct = (struct induction **)
    alloca (nregs * sizeof (struct induction *));
  bzero ((char *)induct_struct, nregs * sizeof (struct induction *));
  class_struct = (struct iv_class **)
    alloca (nregs * sizeof (struct iv_class *));
  bzero ((char *)class_struct, nregs * sizeof (struct iv_class *));

  /* Scan through loop to find all possible bivs.  */

  for (p = NEXT_INSN (loop_start); p != end; p = NEXT_INSN (p))
    {
      if (GET_CODE (p) == INSN
	  && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG)
	{
	  dest_regno = REGNO (SET_DEST (PATTERN (p)));
	  if (induct_var[dest_regno] != NOT_BASIC_INDUCT)
	    {
	      if (basic_induction_var (SET_SRC (PATTERN (p)), dest_regno,
				      &inc_val, &mult_val))
		{
		  /* It is a possible basic induction variable.
		     Create and initialize an induction structure for it.  */

		  struct induction *v =
		    (struct induction *) alloca (sizeof (struct induction));

		  v->insn = p;
		  v->src_regno = dest_regno;
		  v->dest_regno = dest_regno;
		  v->mult_val = mult_val;
		  v->add_val = inc_val;

		  /* Add this to the reg's iv_class, creating a class
		     if this is the first incrementation of the reg.  */

		  bl = class_struct[dest_regno];
		  if (bl)
		    {
		      v->family = bl->biv;
		      bl->biv = v;
		      bl->biv_count++;
		    }
		  else
		    {
		      /* Create and initialize new iv_class.  */

		      bl = (struct iv_class *) alloca (sizeof (struct iv_class));

		      bl->regno = dest_regno;
		      bl->biv = v;
		      v->family = 0;
		      bl->giv = 0;
		      bl->biv_count = 1;
		      bl->giv_count = 0;

		      /* Set initial value to the reg itself.  */
		      bl->initial_value = SET_DEST (PATTERN (p));
		      bl->init_val_set = 0;
		      bl->eliminable = 0;
		      bl->nonneg = 0;

		      /* Add this insn to iv_list.  */
		      bl->next = iv_list;
		      iv_list = bl;

		      /* Put it in the array of iv_lists.  */
		      class_struct[dest_regno] = bl;
		    }

		  induct_var[dest_regno] = BASIC_INDUCT;

		  if (loop_dump_stream)
		    {
		      fprintf (loop_dump_stream,
			       "Insn %d: possible biv, reg %d,",
			       INSN_UID (p), dest_regno);
		      if (GET_CODE (inc_val) == CONST_INT)
			fprintf (loop_dump_stream, " const = %d\n",
				 INTVAL (inc_val));
		      else
			{
			  fprintf (loop_dump_stream, " const = ");
			  print_rtl (loop_dump_stream, inc_val);
			  fprintf (loop_dump_stream, "\n");
			}
		    }
		}
	      else
		induct_var[dest_regno] = NOT_BASIC_INDUCT;
	    }
	}
    }

  /* Scan iv_list to remove all regs that proved not to be bivs.
     Make a sanity check against n_times_set.  */

  biv_found = 0;

  for (backbl = bl = iv_list; bl; backbl = bl, bl = bl->next)
    {
      if (induct_var[bl->regno] != BASIC_INDUCT)
	{
	  /* Not a basic induction variable, remove this iv_class.  */

	  if (backbl == bl)
	    iv_list = bl->next;
	  else
	    backbl->next = bl->next;

	  if (loop_dump_stream)
	    fprintf (loop_dump_stream, "Reg %d: biv discarded, not induct\n",
		    bl->regno);
	}
      else if (n_times_set[bl->regno] != bl->biv_count)
	{
	  /* This happens if register modified by subreg, etc.  */
	  /* Make sure it is not recognized as a basic induction var: */
	  /* remove this iv_class from iv_list.  */

	  induct_var[bl->regno] = NOT_BASIC_INDUCT;

	  if (backbl == bl)
	    iv_list = bl->next;
	  else
	    backbl->next = bl->next;

	  if (loop_dump_stream)
	    fprintf (loop_dump_stream, "Reg %d: biv discarded, count error\n",
		    bl->regno);
	}
      else
	{
	  /* This is a valid basic induction variable.  */

	  biv_found++;

	  if (loop_dump_stream)
	    fprintf (loop_dump_stream, "Reg %d: biv verified\n", bl->regno);
	}
    }

  /* Exit if there are no bivs.  */
  if (!iv_list)
    return;

  /* Find initial value for each biv.  */
  /* Search backwards from loop_start, halting at first label
     or when all bivs have been seen.  */

  p = loop_start;
  while (biv_found)
    {
      p = PREV_INSN (p);
      if (p == 0)
	break;

      if (GET_CODE (p) == INSN
	  && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG)
	{
	  int dest_regno = REGNO (SET_DEST (PATTERN (p)));

	  if (induct_var[dest_regno] == BASIC_INDUCT
	      && class_struct[dest_regno]->init_val_set == 0)
	    {
	      /* This is the first modification found for this reg.  */

	      /* Save value if it is a constant or register.  */
	      if (GET_CODE (SET_SRC (PATTERN (p))) == CONST_INT
		  || GET_CODE (SET_SRC (PATTERN (p))) == REG)
		{
		  class_struct[dest_regno]->initial_value
		    = SET_SRC (PATTERN (p));
		  
		  if (loop_dump_stream)
		    fprintf (loop_dump_stream, "Reg %d: initial value ",
			     dest_regno);
		  if (loop_dump_stream)
		    {
		      if (GET_CODE (SET_SRC (PATTERN (p))) == CONST_INT)
			fprintf (loop_dump_stream, "%d\n", 
				 INTVAL (SET_SRC (PATTERN (p))));
		      else
			fprintf (loop_dump_stream, "reg %d\n", 
				 REGNO (SET_SRC (PATTERN (p))));
		    }
		}
	      else
		{
		  /* Biv initial value is not simple move,
		     so let it keep intial value of "itself".  */

		  if (loop_dump_stream)
		    fprintf (loop_dump_stream, "Reg %d: complex initial value\n",
			     dest_regno);
		}

	      class_struct[dest_regno]->init_val_set = 1;
	      biv_found--;
	    }
	}
      else if (GET_CODE (p) == CODE_LABEL)
	break;
    }

  /* Search the loop for general induction variables.  */

  /* A register is a giv if: it is only set once, it is a function of a
     biv and a constant (or invariant), and it is not a biv.  */

  p = scan_start;
  while (1)
    {
      p = NEXT_INSN (p);
      /* At end of a straight-in loop, we are done.
	 At end of a loop entered at the bottom, scan the top.  */
      if (p == scan_start)
	break;
      if (p == end)
	{
	  if (loop_top != 0)
	    p = NEXT_INSN (loop_top);
	  else
	    break;
	  if (p == scan_start)
	    break;
	}

      /* Look for a general induction variable in a register.  */
      if (GET_CODE (p) == INSN
	  && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG)
	{
	  int src_regno;
	  rtx add_val;
	  rtx mult_val;
	  int benefit;
	  rtx regnote = 0;
	  struct induction *forces = 0;
	  struct induction *forces2 = 0;

	  dest_regno = REGNO (SET_DEST (PATTERN (p)));

	  if (/* Normal giv.  */
	      ((benefit = general_induction_var (SET_SRC (PATTERN (p)),
						 &src_regno, &add_val,
						 &mult_val,
						 &forces, &forces2))
	       /* Giv set with call to a library routine.  */
	       || ((regnote = find_reg_note (p, REG_EQUAL, 0))
		   &&
		   (benefit = general_induction_var (XEXP (regnote, 0),
						     &src_regno,
						     &add_val, &mult_val,
						     &forces, &forces2))))
	      /* Don't recognize a BASIC_INDUCT_VAR here.  */
	      && dest_regno != src_regno
	      /* This must be the only place where the register is set.  */
	      && (n_times_set[dest_regno] == 1
		  || (benefit = consec_sets_giv (benefit, p,
						 src_regno, dest_regno,
						 &add_val, &mult_val))))
	    {
	      int count;
	      struct induction *v =
		(struct induction *) alloca (sizeof (struct induction));
	      rtx temp;

	      record_giv (v, p, src_regno, dest_regno, mult_val, add_val, benefit,
			  forces, forces2, DEST_REG, maybe_never, 0);

	      /* Skip the consecutive insns, if there are any.  */
	      for (count = v->consec - 1; count >= 0; count--)
		{
		  /* If first insn of libcall sequence, skip to end.  */
		  /* Do this at start of loop, since INSN is guaranteed to
		     be an insn here.  */
		  if (temp = find_reg_note (p, REG_LIBCALL, 0))
		    {
		      /* Eliminating a libcall does more good than
			 eliminating a single insn to do the same job.  */
		      benefit += LIBCALL_BENEFIT;
		      p = XEXP (temp, 0);
		    }

		  do p = NEXT_INSN (p);
		  while (GET_CODE (p) == NOTE);
		}
	    }
	}

#ifndef DONT_REDUCE_ADDR
      /* Look for givs which are memory addresses.  */
      /* This resulted in worse code on a VAX 8600.  I wonder if it
	 still does.  */
      if (GET_CODE (p) == INSN)
	find_mem_givs (PATTERN (p), p, maybe_never);
#endif

      /* Past a label or a jump, we get to insns for which we can't count
	 on whether or how many times they will be executed during each
	 iteration.  Givs found afterwards cannot be marked replaceable.  */
      if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
	maybe_never = 1;
    }

  /* Try to prove that the loop counter variable (if any) is always
     nonnegative; if so, record that fact with a REG_NONNEG note
     so that "decrement and branch until zero" insn can be used.  */
  check_dbra_loop (loop_end, iv_list, insn_count, loop_start);

  /* Create reg_map to hold substitutions for replaceable giv regs.  */
  reg_map = (rtx *) alloca (nregs * sizeof (rtx));
  bzero ((char *)reg_map, nregs * sizeof (rtx));

  /* Examine each iv class for feasibility of strength reduction/induction
     variable elimination.  */

  for (bl = iv_list; bl; bl = bl->next)
    {
      struct induction *v;
      int benefit;
      int replaceable;
      int all_reduced;
      rtx final_value = 0;

      /* Test whether it will be possible to eliminate this biv
	 provided all givs are reduced.  This is possible if either
	 the reg is not used outside the loop, or we can compute
	 what its final value will be.

	 Don't try if we put a REG_NONNEG note on the endtest for this biv.
	 ??? That should be only on machines that have dbra insns.  */

      if ((uid_luid[regno_last_uid[bl->regno]] < INSN_LUID (loop_end)
	   && uid_luid[regno_first_uid[bl->regno]] > INSN_LUID (loop_start)
	   && bl->init_val_set && ! bl->nonneg)
	  || (final_value = final_biv_value (bl, loop_end)))
	{
	  /* Get the REG rtx for the biv.  */
	  rtx reg = SET_DEST (PATTERN (bl->biv->insn));

	  for (p = loop_start; p != end; p = NEXT_INSN (p))
	    {
	      enum rtx_code code = GET_CODE (p);
	      if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
		  && reg_mentioned_p (reg, PATTERN (p)))
		{
		  /* This insn uses the biv.  If we can't understand it,
		     then we can't eliminate the biv.  */
		  if (GET_CODE (PATTERN (p)) != SET)
		    break;

		  /* The insns that increment the biv are no problem.  */
		  if (SET_DEST (PATTERN (p)) == reg)
		    continue;

		  /* If can rewrite this insn not to use the biv, it's ok.  */
		  if (can_eliminate_biv_p (p, bl))
		    continue;

		  /* If this is an insn which computes a giv, no problem,
		     because it will go away if the giv is reduced.  */
		  for (v = bl->giv; v; v = v->family)
		    if (!v->ignore && v->insn == p && v->giv_type == DEST_REG)
		      break;
		  if (v)
		    continue;

		  /* Biv is used in a way we cannot eliminate.  */
		  break;
		}
	    }

	  if (p == end)
	    {
	      bl->eliminable = 1;
	      if (loop_dump_stream)
		fprintf (loop_dump_stream, "Can eliminate biv %d.\n",
			 bl->regno);
	    }
	  else if (loop_dump_stream)
	    fprintf (loop_dump_stream,
		     "Cannot eliminate biv %d due to insn %d.\n",
		     bl->regno, INSN_UID (p));
	}
      else
	{
	  if (loop_dump_stream)
	    fprintf (loop_dump_stream,
		     "Cannot eliminate biv %d: used outside the loop\n",
		     bl->regno);
	}

      /* This will be true at the end, if all givs which depend on this
	 biv have been strength reduced.
	 We can't (currently) eliminate the biv unless this is so.  */
      all_reduced = 1;

      /* Check each giv in this class.  */

      for (v = bl->giv; v; v = v->family)
	{
	  struct induction *tv;

	  if (v->ignore)
	    continue;

	  benefit = v->benefit;
	  replaceable = v->replaceable;

	  /* Reduce benefit if not replaceable, since we will insert
	     a move-insn to replace the insn that calculates this giv.  */
	  if (!replaceable && ! bl->eliminable)
	    benefit -= COPY_PENALTY;

	  /* Decrease the benefit to count the add-insns that we will
	     insert to increment the reduced reg for the giv.  */
	  benefit -= ADD_BENEFIT * bl->biv_count;

	  /* Find all equivalent givs (that bear same relation to the biv).
	     Link them via the `same' field and add their benefits together.
	     They can be replaced with a single register.  */

	  for (tv = v->family; tv; tv = tv->family)
	    {
	      if (tv->ignore == 0
		  && tv->src_regno == v->src_regno
		  && rtx_equal_p (tv->mult_val, v->mult_val)
		  && rtx_equal_p (tv->add_val, v->add_val))
		{
		  benefit += tv->benefit;
		  if (! tv->replaceable)
		    benefit -= COPY_PENALTY;
		  v->lifetime += tv->lifetime;
		  v->times_used += tv->times_used;
		  tv->ignore = 1;

		  /* Link them together via `same' field.  */
		  tv->same = v->same;
		  v->same = tv;

		  if (loop_dump_stream)
		    fprintf (loop_dump_stream,
			     "giv of insn %d combined with that of %d.\n",
			     INSN_UID (v->insn), INSN_UID (tv->insn));
		}
	    }

	  /* Decide whether to strength-reduce this giv
	     or to leave the code unchanged
	     (recompute it from the biv each time it is used).
	     This decision can be made independently for each giv.  */

	  /* ??? Perhaps attempt to guess whether autoincrement will handle
	     some of the new add insns; if so, can increase BENEFIT
	     (undo the subtraction of ADD_BENEFIT that was done above).  */

	  /* Is it right to consider times_used?  */

	  if (benefit <= 0)
	    {
	      if (loop_dump_stream)
		fprintf (loop_dump_stream, "giv of insn %d, no benefit\n",
			 INSN_UID (v->insn));
	      v->ignore = 1;
	    }

	  if (v->lifetime * threshold * benefit < insn_count)
	    {
	      if (loop_dump_stream)
		fprintf (loop_dump_stream,
			 "giv of insn %d not worth while, %d vs %d.\n",
			 INSN_UID (v->insn),
			 v->lifetime * threshold * benefit, insn_count);
	      v->ignore = 1;
	    }

	  /* Now check that we can increment the reduced giv
	     without needing a multiply insn.  If not, reject it.  */

	  if (! v->ignore)
	    {
	      int success = 1;

	      for (tv = bl->biv; tv; tv = tv->family)
		if (tv->mult_val == const1_rtx)
		  success &= product_cheap_p (tv->add_val, v->mult_val);

	      if (! success)
		{
		  if (loop_dump_stream)
		    fprintf (loop_dump_stream,
			     "giv of insn %d: would need a multiply.\n",
			     INSN_UID (v->insn));
		  v->ignore = 1;
		}
	    }
	}

      /* Reduce each giv that we decided to reduce.  */

      for (v = bl->giv; v; v = v->family)
	{
	  struct induction *tv;
	  if (! v->ignore)
	    {
	      rtx new_reg = gen_reg_rtx (v->giv_type == DEST_ADDR ? Pmode
					 : GET_MODE (SET_DEST (PATTERN (v->insn))));

	      /* For each place where the biv is incremented,
		 add an insn to increment the new, reduced reg for the giv.
		 Insert it before the insn that sets the biv,
		 so that the biv increment remains last before the endtest,
		 so that dbra will still be recognized.  */

	      for (tv = bl->biv; tv; tv = tv->family)
		{
		  if (tv->mult_val == const1_rtx)
		    emit_iv_inc (tv->add_val, v->mult_val,
				 new_reg, tv->insn);
		  else /* tv->mult_val == const0_rtx */
		    /* A multiply is acceptable here
		       since this is presumed to be seldom executed.  */
		    emit_iv_init_code (tv->add_val, v->mult_val,
				       v->add_val, new_reg, tv->insn);
		}

	      /* Add code at loop start to initialize giv's reduced reg.  */

	      emit_iv_init_code (bl->initial_value, v->mult_val,
				 v->add_val, new_reg, loop_start);

	      /* For each giv register that can be reduced now:
		 delete old insn that modifies the giv,
		 if replaceable, substitute reduced reg
		   wherever the old giv occurs;
		 else add new move insn "giv_reg = reduced_reg".  */

	      for (tv = v; tv; tv = tv->same)
		{
		  /* Record the identity of the reduced reg.  */
		  tv->new_reg = new_reg;

		  if (tv->giv_type == DEST_ADDR)
		    {
		      /* Store reduced reg as the address in the memref
			 where we found this giv.  */
		      * tv->location = new_reg;
		    }
		  else if (tv->replaceable)
		    {
		      reg_map[tv->dest_regno] = new_reg;
		      /* If giv lives after end of loop,
			 emit insn to copy reduced reg into old reg,
			 at the end of the loop.  */
		      if (uid_luid[regno_last_uid[tv->dest_regno]]
			  > uid_luid[INSN_UID (loop_end)])
			emit_insn_after (gen_rtx (SET, VOIDmode,
						  SET_DEST (PATTERN (tv->insn)),
						  new_reg),
					 loop_end);
		    }
		  else
		    {
		      emit_insn_before (gen_rtx (SET, VOIDmode,
						SET_DEST (PATTERN (tv->insn)),
						new_reg),
				       tv->insn);
		    }

		  /* Delete the insn that used to set the old giv reg,
		     unless we modified an address in it.
		     In any case, delete the other insns used for this one.  */
		  delete_insn_forces (tv, tv->giv_type != DEST_ADDR);

		  if (loop_dump_stream)
		    fprintf (loop_dump_stream, "giv at %d reduced to reg %d\n",
			     INSN_UID (tv->insn), REGNO (new_reg));
		}
	      /* One set of equivalent givs has been strength-reduced.  */
	    }
	  else if (v->new_reg == 0)
	    {
	      /* This giv wasn't reduced and is not worth reducing.  */

	      for (tv = v; tv; tv = tv->same)
		if (loop_dump_stream)
		  fprintf (loop_dump_stream, "giv at %d not reduced\n",
			   INSN_UID (tv->insn));

	      all_reduced = 0;
	    }
	}

      /* All the givs in this family have been reduced if they merit it.  */

      /* Try to eliminate the biv, if it is a candidate.
	 This won't work if ! all_reduced,
	 since the givs we planned to use might not have been reduced.  */

      if (all_reduced == 1 && bl->eliminable)
	{
	  /* Get the REG rtx for the biv.  */
	  rtx reg = SET_DEST (PATTERN (bl->biv->insn));

	  for (p = loop_start; p != end; p = NEXT_INSN (p))
	    {
	      enum rtx_code code = GET_CODE (p);
	      if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
		  && reg_mentioned_p (reg, PATTERN (p))
		  && SET_DEST (PATTERN (p)) == cc0_rtx)
		/* Found a compare instruction using this biv;
		   rewrite it to use a related giv.  */
		eliminate_biv (p, bl, loop_start);
	    }

	  /* Biv is no longer really needed inside the loop,
	     so delete all insns that set the biv.  */

	  for (v = bl->biv; v; v = v->family)
	    delete_insn (v->insn);

	  /* If final_value != 0, then biv may be used after loop end
	     and we must emit an insn to set it just in case.  */
	  if (final_value != 0)
	    emit_insn_after (gen_rtx (SET, VOIDmode, reg, final_value),
			     loop_end);

	  if (loop_dump_stream)
	    fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
		     bl->regno);
	}
    }

  /* Go through all the instructions in the loop, making all the
     register substitutions scheduled in REG_MAP.  */

  for (p = loop_start; p != end; p = NEXT_INSN (p))
    if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
 	|| GET_CODE (p) == CALL_INSN)
      replace_regs (PATTERN (p), reg_map, nregs);
}

/* Scan X for memory refs and check each memory address
   as a possible giv.  INSN is the insn whose pattern X comes from.
   MAYBE_NEVER is 1 if the loop might execute INSN zero times.  */

static void
find_mem_givs (x, insn, maybe_never)
     rtx x;
     rtx insn;
     int maybe_never;
{
  register int i, j;
  register enum rtx_code code;
  register char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);
  switch (code)
    {
    case REG:
    case CONST_INT:
    case CONST:
    case CONST_DOUBLE:
    case SYMBOL_REF:
    case LABEL_REF:
    case PC:
    case CC0:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case USE:
    case CLOBBER:
      return;

    case MEM:
      {
	int src_regno;
	rtx add_val;
	rtx mult_val;
	int benefit;
	struct induction *forces = 0;
	struct induction *forces2 = 0;

	benefit = general_induction_var (XEXP (x, 0),
					 &src_regno, &add_val, &mult_val,
					 &forces, &forces2);
	if (benefit > 0)
	  {
	    /* Found one; record it.  */
	    struct induction *v =
	      (struct induction *) oballoc (sizeof (struct induction));

	    record_giv (v, insn, src_regno, 0, mult_val, add_val, benefit,
			forces, forces2, DEST_ADDR, maybe_never, &XEXP (x, 0));
	  }
	return;
      }
    }

  /* Recursively scan the subexpressions for other mem refs.  */

  fmt = GET_RTX_FORMAT (code);
  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    if (fmt[i] == 'e')
      find_mem_givs (XEXP (x, i), insn, maybe_never);
    else if (fmt[i] == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	find_mem_givs (XVECEXP (x, i, j), insn, maybe_never);
}

/* Fill in the data about one giv.
   V is the `struct induction' in which we record the giv.  (It is
   allocated by the caller, with alloca.)
   INSN is the insn that sets it.
   BENEFIT estimates the savings from deleting this insn.
   TYPE is DEST_REG or DEST_ADDR; it says whether the giv is computed
   into a register or is used as a memory address.

   SRC_REGNO is the biv reg number which the giv is computed from.
   DEST_REGNO is the giv's reg number (if the giv is stored in a reg).
   MULT_VAL and ADD_VAL are the coefficients used to compute the giv.
   FORCES and FORCES2, if nonzero, are other `struct induction's for
   other givs which are used to compute this giv indirectly.
   LOCATION points to the place where this giv's value appears in INSN.  */

static void
record_giv (v, insn, src_regno, dest_regno, mult_val, add_val, benefit,
	    forces, forces2, type, maybe_never, location)
     struct induction *v;
     rtx insn;
     int src_regno, dest_regno;
     rtx mult_val, add_val;
     int benefit;
     struct induction *forces, *forces2;
     enum g_types type;
     int maybe_never;
     rtx *location;
{
  struct induction *b;
  struct iv_class *bl;

  v->insn = insn;
  v->src_regno = src_regno;
  v->giv_type = type;
  v->dest_regno = dest_regno;
  v->mult_val = mult_val;
  v->add_val = add_val;
  v->benefit = benefit;
  v->location = location;

  if (type == DEST_ADDR)
    {
      v->consec = 0;
      v->lifetime = 1;
      v->times_used = 1;
    }
  else
    {
      v->consec = n_times_set[dest_regno] - 1;
      v->lifetime = (uid_luid[regno_last_uid[dest_regno]]
		     - uid_luid[regno_first_uid[dest_regno]]);
      v->times_used = n_times_used[dest_regno];
    }

  v->same = 0;
  v->forces = 0;
  v->forces2 = 0;
  v->ignore = 0;
  v->new_reg = 0;

  /* Mark giv as forced if it is only used to compute another giv.  */

  /* This check is not sufficient as INSN may have been moved giving
     it a new uid, so make another check by calculating lifetimes.
     This is overconservative but seems to be correct.  */

  if (forces)
    {
      v->benefit += forces->benefit;
      if ((regno_last_uid[forces->dest_regno] == INSN_UID (insn)
	   ||
	   ((uid_luid[regno_last_uid[forces->dest_regno]]
	     - uid_luid[regno_first_uid[forces->dest_regno]])
	    == (INSN_UID (insn) - INSN_UID (forces->insn))))
	  && !reg_used_between_p (SET_DEST (PATTERN (forces->insn)),
				  forces->insn, insn))
 	{
	  v->forces = forces;
	  forces->ignore = 1;
 	}
    }

  if (forces2)
    {
      v->benefit += forces2->benefit;
      if ((regno_last_uid[forces2->dest_regno] == INSN_UID (insn)
	   ||
	   ((uid_luid[regno_last_uid[forces2->dest_regno]]
	     - uid_luid[regno_first_uid[forces2->dest_regno]])
	    == (INSN_UID (insn) - INSN_UID (forces2->insn))))
	  && !reg_used_between_p (SET_DEST (PATTERN (forces2->insn)),
				  forces2->insn, insn))
 	{
	  if (v->forces)
	    v->forces2 = forces2;
	  else
	    v->forces = forces2;
	  forces2->ignore = 1;
	}
    }

  if (type == DEST_REG)
    {
      induct_var[dest_regno] = GENERAL_INDUCT;
      induct_struct[dest_regno] = v;
    }

  /* Add the giv to the class of givs computed from one biv.  */

  bl = class_struct[src_regno];
  if (bl)
    {
      v->family = bl->giv;
      bl->giv = v;
      bl->giv_count++;
      bl->total_benefit += benefit;
    }
  else
    {
      /* Fatal error, biv missing for this giv?  */
      fflush (loop_dump_stream);
      abort ();
    }

  if (type == DEST_ADDR)
    v->replaceable = 1;
  else
    {
      /* The giv can be replaced outright by the reduced register if
 	 - the insn that sets the giv is always executed,
 	 - the giv is not used before the insn that sets it,
 	    i.e. no definition outside loop reaches into loop
	 - no assignments to the biv occur during the giv's lifetime.  */

      if (!maybe_never
	  /* This always fails if INSN was moved by loop opt.  */
	  && (regno_first_uid[dest_regno] == INSN_UID (insn)))
 	{
	  v->replaceable = 1;
	  for (b = bl->biv; b; b = b->family)
	    {
	      if ((uid_luid[INSN_UID (b->insn)] >= uid_luid[regno_first_uid[dest_regno]])
		  &&
		  (uid_luid[INSN_UID (b->insn)]
		   <= uid_luid[regno_last_uid[dest_regno]]))
		{
		  v->replaceable = 0;
		  break;
 		}
	    }
	}
      else
 	v->replaceable = 0;
    }

  if (loop_dump_stream)
    {
      if (type == DEST_REG)
 	fprintf (loop_dump_stream, "Insn %d: giv reg %d",
		 INSN_UID (insn), dest_regno);
      else
 	fprintf (loop_dump_stream, "Insn %d: dest address",
 		 INSN_UID (insn));

      fprintf (loop_dump_stream, " src reg %d benefit %d",
	       src_regno, v->benefit);
      fprintf (loop_dump_stream, " used %d lifetime %d",
	       v->times_used, v->lifetime);

      if (v->replaceable)
 	fprintf (loop_dump_stream, " replaceable");

      if (GET_CODE (mult_val) == CONST_INT)
	fprintf (loop_dump_stream, " mult %d",
 		 INTVAL (mult_val));
      else
	{
	  fprintf (loop_dump_stream, " mult ");
	  print_rtl (loop_dump_stream, mult_val);
	}

      if (GET_CODE (add_val) == CONST_INT)
	fprintf (loop_dump_stream, " add %d",
		 INTVAL (add_val));
      else
	{
	  fprintf (loop_dump_stream, " add ");
	  print_rtl (loop_dump_stream, add_val);
	}
    }

  if (loop_dump_stream && v->forces)
    fprintf (loop_dump_stream, " forces insn %d", INSN_UID (v->forces->insn));
  if (loop_dump_stream && v->forces2)
    fprintf (loop_dump_stream, " forces insn %d", INSN_UID (v->forces2->insn));
  if (loop_dump_stream && v->consec)
    fprintf (loop_dump_stream, " consec %d", v->consec);
  if (loop_dump_stream)
    fprintf (loop_dump_stream, "\n");
}

/* Delete the insns forced by the insn described by V.
   If THIS_TOO is nonzero, delete that insn itself as well.  */

static void
delete_insn_forces (v, this_too)
     struct induction *v;
     int this_too;
{
  rtx x, p;
  int count;
  rtx insn;

  if (this_too)
    {
      insn = v->insn;
      for (count = v->consec; count >= 0; count--)
	{
	  /* If first insn of libcall sequence, skip to end.  */
	  /* Do this at start of loop, since p is guaranteed to
	     be an insn here.  */
	  if (x = find_reg_note (insn, REG_LIBCALL, 0))
	    insn = XEXP (x, 0);

	  if (x = find_reg_note (insn, REG_EQUAL, 0))
	    {
	      /* This is a library call; delete all insns backward until get to
		 first insn in this group.  */
	      rtx first = XEXP (find_reg_note (insn, REG_RETVAL, 0), 0);
	      for (p = insn; p != first; p = PREV_INSN (p))
		delete_insn (p);
	      /* Delete first insn also.  */
	      delete_insn (p);
	    }
	  else
	    delete_insn (insn);

	  do insn = NEXT_INSN (insn);
	  while (GET_CODE (insn) == NOTE);
	}
    }

  if (v->forces)
    delete_insn_forces (v->forces, 1);
  if (v->forces2)
    delete_insn_forces (v->forces2, 1);
}

/* Check whether an insn is an increment legitimate for a basic induction var.
   X is the source of the insn.
   DEST_REG is the putative biv, also the destination of the insn.
   We accept patterns of these forms:
     REG = REG + INVARIANT
     REG = INVARIANT + REG
     REG = REG - CONSTANT

   If X is suitable, we return 1,
   and store the factor multiplying REF in X into *MULT_VAL
   and the additive term into *INC_VAL.
   Otherwise we return 0.  */

static int
basic_induction_var (x, dest_regno, inc_val, mult_val)
     register rtx x;
     int dest_regno;
     rtx *inc_val;
     rtx *mult_val;
{
  register RTX_CODE code = GET_CODE (x);
  rtx arg;

  switch (code)
    {
    case PLUS:
      if (GET_CODE (XEXP (x, 0)) == REG
	  && REGNO (XEXP (x, 0)) == dest_regno)
 	arg = XEXP (x, 1);
      else if (GET_CODE (XEXP (x, 1)) == REG
	       && REGNO (XEXP (x, 1)) == dest_regno)
	arg = XEXP (x, 0);
      else
 	return 0;

      if (invariant_p (arg) == 1)
	*inc_val = arg;
      else
	return 0;

      *mult_val = const1_rtx;
      return 1;

    case MINUS:
      if (GET_CODE (XEXP (x, 0)) == REG
 	  && REGNO (XEXP (x, 0)) == dest_regno
 	  && GET_CODE (XEXP (x, 1)) == CONST_INT)
 	*inc_val = gen_rtx (CONST_INT, VOIDmode,
			    - INTVAL (XEXP (x, 1)));
      else
 	return 0;
      *mult_val = const1_rtx;
      return 1;

      /* Can accept constant setting of biv only when inside inner most loop.
  	 Otherwise, a biv of an inner loop may be incorrectly recognized
	 as a biv of the outer loop,
	 causing code to be moved INTO the inner loop.  */
    case REG:
      if (!invariant_p (x))
	return 0;
    case CONST_INT:
    case SYMBOL_REF:
    case CONST:
      if (loops_enclosed == 1)
 	{
	  *inc_val = x;
 	  *mult_val = const0_rtx;
 	  return 1;
 	}
      else
 	return 0;

    default:
      return 0;
    }
}

/* A general induction variable (giv) is any quantity that is a linear function
   of a basic induction variable, i.e. giv = biv * mult_val + add_val.
   The coefficients can be any loop invariant quantity.
   A giv need not be computed directly from the biv;
   it can be computed by way of other givs.  */

/* Determine whether X computes a giv.
   If it does, return a nonzero value
     which is the benefit from eliminating the computation of X;
   set *SRC_REGNO to the register number of the biv that it is computed from;
   set *ADD_VAL and *MULT_VAL to the coefficients,
     such that the value of X is biv * mult + add;
   set forces (and forces2) to identify any other givs that are used
     solely to compute this one.  */

/* This routine recognizes four types of patterns that generate givs:
   - giv = biv op invariant             v = 0,    g = 0
   - giv1 = giv2 op invariant           v = 0,    g = giv2
       where giv1 and giv2 are functions of the same biv
   - giv1 = biv op giv2                 v = giv2, g = 0
       where giv2 is a function of biv
   - giv1 = giv2 op giv3                v = giv3, g = giv2
       where giv2 and giv3 are functions of the save biv  */

static int
general_induction_var (x, src_regno, add_val, mult_val, forces, forces2)
     rtx x;
     int *src_regno;
     rtx *add_val;
     rtx *mult_val;
     struct induction **forces;
     struct induction **forces2;
{
  register RTX_CODE code = GET_CODE (x);
  rtx arg;
  struct induction *g = 0;
  struct induction *v = 0;
  int subexp = 0;
  int tem;

  switch (code)
    {
    case NEG:
      /* This can generate givs also, but it is not handled.  */
      return 0;

    case PLUS:
    case MINUS:
    case MULT:
    case UMULT:
      /* Result is linear in both operands.  */
      /* Determine which operand is the biv, and put the other in ARG.  */
      if (GET_CODE (XEXP (x, 0)) == REG
	  && induct_var[REGNO (XEXP (x, 0))] == BASIC_INDUCT)
	{
	  *src_regno = REGNO (XEXP (x, 0));
	  arg = XEXP (x, 1);

	}
      else if (GET_CODE (XEXP (x, 1)) == REG
	       && induct_var[REGNO (XEXP (x, 1))] == BASIC_INDUCT)
	{
	  *src_regno = REGNO (XEXP (x, 1));
	  arg = XEXP (x, 0);

	}
      /* Check for an rtl subexpression that is a giv.  Memory address
	 givs often look like (plus (reg) (mult (biv) (const))).  */
      /* Do this before checking for a giv operand, as this function will
	 fail if this special operand is not recognized.  */
#ifndef DONT_REDUCE_ADDR
      else if (tem = general_induction_var (XEXP (x, 1), src_regno,
					    add_val, mult_val,
					    forces, forces2))
	{
	  /* Set subexp true so that this can be handled a little
	     differently from the normal case of g set.  */
	  /* Note that SRC_REGNO is already set.  */
	  subexp = TRUE;
	  g = (struct induction *) alloca (sizeof (struct induction));
	  g->mult_val = *mult_val;
	  g->add_val = *add_val;
	  /* Count this multiply as a shift, since that's what it
	     really will do.  */
	  if (tem == MULT_BENEFIT)
	    g->benefit = SHIFT_BENEFIT;
	  else
	    g->benefit = tem;
	  arg = XEXP (x, 0);
	}
#endif
      /* Also allow general induction variables.
	 Could have a mult followed by an add (i.e. an address calculation),
	 thereby generating two related general induction variables
	 of which only the second is actually used.  */
      /* Do this after checking both args for basic induction variables.  */
      else if (GET_CODE (XEXP (x, 0)) == REG
	       && induct_var[REGNO (XEXP (x, 0))] == GENERAL_INDUCT)
	{
	  g = induct_struct[REGNO (XEXP (x, 0))];
	  *src_regno = g->src_regno;
	  arg = XEXP (x, 1);
	}
      else if (GET_CODE (XEXP (x, 1)) == REG
	       && induct_var[REGNO (XEXP (x, 1))] == GENERAL_INDUCT)
	{
	  g = induct_struct[REGNO (XEXP (x, 1))];
	  *src_regno = g->src_regno;
	  arg = XEXP (x, 0);
	}
      else
	return 0;

      /* Overall form of expression looks good.  */
      break;

      /* Could handle these also.  */
    case DIV:
    case UDIV:
      /* For a 68020 could handle these? */
    case LSHIFT:
    case ASHIFT:
    case ASHIFTRT:
    case LSHIFTRT:
      /* These operations are linear only in first operand.
	 Check for a biv or giv there; if found, put other operand in ARG.  */
      if (GET_CODE (XEXP (x, 0)) == REG
	  && induct_var[REGNO (XEXP (x, 0))] == BASIC_INDUCT)
	{
	  *src_regno = REGNO (XEXP (x, 0));
	  arg = XEXP (x, 1);
	}
      /* Also allow general induction variable.  */
      else if (GET_CODE (XEXP (x, 0)) == REG
	       && induct_var[REGNO (XEXP (x, 0))] == GENERAL_INDUCT)
	{
	  g = induct_struct[REGNO (XEXP (x, 0))];
	  *src_regno = g->src_regno;
	  arg = XEXP (x, 1);
	}
      else
	return 0;

      /* Overall form of expression looks good.  */
      break;

    default:
      return 0;
    }

  /* ARG is the operand that is NOT a biv or giv.
     Test it for superficial validity.  */

  /* This is just a special case of invariant values,
     it is not really needed, but it's a shortcut.  */
  if (GET_CODE (arg) == CONST_INT)
    ;

  /* Depends on previous general induction variable, which has
     the same basic induction variable */
  /* This code detects mults that have been generated as shift and add.  */
  else if (GET_CODE (arg) == REG
	   && induct_var[REGNO (arg)] == GENERAL_INDUCT
	   && induct_struct[REGNO (arg)]->src_regno == *src_regno)
    {
      v = induct_struct[REGNO (arg)];
      /* Dependence indicated by forces, sort of kludgey.  */
    }

  /* Invariant expression, could be a constant-valued register. */
  else if (invariant_p (arg) == 1)
    ;

  /* Failure */
  else
    return 0;

  /* Now we know looks like a giv; extract the coefficients.
     We can still fail if the coefficients are not what we can handle.  */

  /* Only succeed if result mult_val and add_val are only one level of rtl,
     for example, (NEG:SI (REG:SI 34)) is not accepted.
     This mainly causes problems with the MINUS code.  */

  switch (code)
    {
    case PLUS:
      if (v && g)
	{
	  if (GET_CODE (g->mult_val) == CONST_INT)
	    {
	      if (g->mult_val == const0_rtx)
		*mult_val = v->mult_val;
	      else if (GET_CODE (v->mult_val) == CONST_INT)
		*mult_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->mult_val)
				       + INTVAL (v->mult_val));
	      else
		return 0;
	    }
	  else if (v->mult_val == const0_rtx)
	    *mult_val = g->mult_val;
	  else
	    return 0;

	  if (GET_CODE (g->add_val) == CONST_INT)
	    {
	      if (g->add_val == const0_rtx)
		*add_val = v->add_val;
	      else if (GET_CODE (v->add_val) == CONST_INT)
		*add_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->add_val)
				       + INTVAL (v->add_val));
	      else
		return 0;
	    }
	  else if (v->add_val == const0_rtx)
	    *add_val = g->add_val;
	  else
	    return 0;

	  if (subexp)
	    {
	      /* g deleted when return, can't return pointer to it */
	      if (*forces2 == 0)
		*forces2 = v;
	      return ADD_BENEFIT + g->benefit;
	    }
	  else
	    {
	      *forces = g;
	      *forces2 = v;
	      return ADD_BENEFIT;
	    }
	}
      else if (v)
	{
	  if (GET_CODE (v->mult_val) == CONST_INT)
	    *mult_val = gen_rtx (CONST_INT, VOIDmode,
				   INTVAL (v->mult_val) + 1);
	  else
	    return 0;
	  *add_val = v->add_val;
	  *forces = v;
	  return ADD_BENEFIT;
	}
      else if (g)
	{
	  *mult_val = g->mult_val;
	  if (GET_CODE (g->add_val) == CONST_INT)
	    {
	      if (g->add_val == const0_rtx)
		*add_val = arg;
	      else if (GET_CODE (arg) == CONST_INT)
		*add_val = gen_rtx (CONST_INT, VOIDmode,
				      INTVAL (g->add_val) + INTVAL (arg));
	      else
		return 0;
	    }
	  else
	    /* Could succeed if arg == 0, but that will never occur.  */
	    return 0;

	  if (subexp)
	    /* g deleted when return, can't return pointer to it */
	    return ADD_BENEFIT + g->benefit;
	  else
	    {
	      *forces = g;
	      return ADD_BENEFIT;
	    }
	}
      else
	{
	  *mult_val = const1_rtx;
	  *add_val = arg;
	  return ADD_BENEFIT;
	}

      /* Takes a lot of code and will rarely succeed.  */
    case MINUS:
      if (v && g)
	{
	  /* G is the first argument of MINUS.  */

	  if (GET_CODE (g->mult_val) == CONST_INT)
	    {
	      if (g->mult_val == const0_rtx)
#if 0 /* Should not have to fail here */
		*mult_val = gen_rtx (NEG, SImode, v->mult_val);
#endif
		return 0;
	      else if (GET_CODE (v->mult_val) == CONST_INT)
		*mult_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->mult_val)
				       - INTVAL (v->mult_val));
	      else
		return 0;
	    }
	  else if (v->mult_val == const0_rtx)
	    *mult_val = g->mult_val;
	  else
	    return 0;

	  if (GET_CODE (g->add_val) == CONST_INT)
	    {
	      if (g->add_val == const0_rtx)
#if 0 /* should not have to fail here */
		*add_val = v->add_val;
#endif
		return 0;
	      else if (GET_CODE (v->add_val) == CONST_INT)
		*add_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->add_val)
				       - INTVAL (v->add_val));
	      else
		return 0;
	    }
	  else if (v->add_val == const0_rtx)
	    *add_val = g->add_val;
	  else
	    return 0;

	  if (subexp)
	    {
	      /* G deleted when return, can't return pointer to it */
	      if (*forces2 == 0)
		*forces2 = v;
	      return ADD_BENEFIT + g->benefit;
	    }
	  else
	    {
	      *forces = g;
	      *forces2 = v;
	      return ADD_BENEFIT;
	    }
	}
      else if (v)
	{
	  if (GET_CODE (v->mult_val) != CONST_INT)
	    return 0;
	  if (arg == XEXP (x, 0))             /* giv1 = giv2 - biv */
	    {
	      *mult_val = gen_rtx (CONST_INT, VOIDmode,
				     INTVAL (v->mult_val) - 1);
	      *add_val = v->add_val;
	    }
	  else                                /* giv1 = biv - giv2 */
	    {
	      *mult_val = gen_rtx (CONST_INT, VOIDmode,
				     1 - INTVAL (v->mult_val));
	      if (GET_CODE (v->add_val) == CONST_INT)
		*add_val = gen_rtx (CONST_INT, VOIDmode,
				      - INTVAL (v->add_val));
	      else
		return 0;
	    }
	  *forces = v;
	  return ADD_BENEFIT;
	}
      else if (g)
	{
	  if (arg == XEXP (x, 1))
	    *mult_val = g->mult_val;
	  else
	    {
	      if (GET_CODE (g->mult_val) == CONST_INT)
		*mult_val = gen_rtx (CONST_INT, VOIDmode,
				       - INTVAL (g->mult_val));
	      else
		return 0;
	    }
	  if (GET_CODE (g->add_val) == CONST_INT)
	    {
	      if (g->add_val == const0_rtx)
		{
		  if (arg == XEXP (x, 1))    /* giv1 = giv2 - arg */
		    {
		      /* Fail unless arg is a constant.  */
		      if (GET_CODE (arg) == CONST_INT)
			*add_val = gen_rtx (CONST_INT, VOIDmode,
					      -INTVAL (arg));
		      else
			return 0;
		    }
		  else                       /* giv1 = arg - giv2 */
		    *add_val = arg;
		}
	      else if (GET_CODE (arg) == CONST_INT)
		{
		  if (arg == XEXP (x, 1))   /* giv1 = giv2 - arg */
		    *add_val = gen_rtx (CONST_INT, VOIDmode,
					  INTVAL (g->add_val)
					  - INTVAL (arg));
		  else                      /* giv1 = arg - giv2 */
		    *add_val = gen_rtx (CONST_INT, VOIDmode,
					  INTVAL (arg),
					  - INTVAL (g->add_val));
		}
	      else
		return 0;
	    }
	  else
	    /* Could succeed if arg == 0, but that will never occur.  */
	    return 0;

	  if (subexp)
	    /* G deleted when return, can't return pointer to it.  */
	    return ADD_BENEFIT + g->benefit;
	  else
	    {
	      *forces = g;
	      return ADD_BENEFIT;
	    }
	}
      else if (GET_CODE (arg) == CONST_INT)
	{
	  if (arg == XEXP (x, 1))
	    {
	      *add_val = gen_rtx (CONST_INT, VOIDmode, - INTVAL (arg));
	      *mult_val = const1_rtx;
	    }
	  else
	    {
	      *add_val = arg;
	      *mult_val = gen_rtx (CONST_INT, VOIDmode, -1);
	    }
	  return ADD_BENEFIT;
	}
      else
	  return 0;

      /* UMULT can be handled like MULT since C ignores overflows.  */
    case MULT:
    case UMULT:
      if (v && g)
	{
	  /* Quadratic term, just fail.  */
	  return 0;
	}
      else if (v)
	{
	  /* Quadratic term, just fail.  */
	  return 0;
	}
      else if (g)
	{
	  /* Takes a lot of code and will rarely succeed.  */
	  /* dest = m * arg * b + a * arg */
	  if (GET_CODE (g->mult_val) == CONST_INT)
	    {
	      if (g->mult_val == const0_rtx)
		*mult_val = const0_rtx;
	      else if (g->mult_val == const1_rtx)
		*mult_val = arg;
	      else if (GET_CODE (arg) == CONST_INT)
		*mult_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->mult_val) * INTVAL (arg));
	      else
		return 0;
	    }
	  else
	    /* Could suceed if arg == 1 or 0, but this will never occur.  */
	    return 0;

	  if (GET_CODE (g->add_val) == CONST_INT)
	    {
	      if (g->add_val == const0_rtx)
		*add_val = const0_rtx;
	      else if (g->add_val == const1_rtx)
		*add_val = arg;
	      else if (GET_CODE (arg) == CONST_INT)
		*add_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->add_val) * INTVAL (arg));
	      else
		return 0;
	    }
	  else
	    /* Could suceed if arg == 1 or 0, but this will never occur.  */
	    return 0;

	  if (subexp)
	    /* G deleted when return, can't return pointer to it.  */
	    return MULT_BENEFIT + g->benefit;
	  else
	    {
	      *forces = g;
	      return MULT_BENEFIT;
	    }
	}
      else
	{
	  *mult_val = arg;
	  *add_val = const0_rtx;
	  return MULT_BENEFIT;
	}

      /* These are not worth the trouble.  */
    case DIV:
    case UDIV:
      return 0;

      /* Handle these, but only for left shift.  */
    case LSHIFT:
    case ASHIFT:
      if (v && g)
	{
	  /* Quadratic term, just fail.  */
	  return 0;
	}
      else if (v)
	{
	  /* Quadratic term, just fail.  */
	  return 0;
	}
      else if (g)
	{
	  /* Takes a lot of code and will rarely succeed.  */
	  /* dest = ((m * b) << arg) + (a << arg) */
	  if (GET_CODE (g->mult_val) == CONST_INT)
	    {
	      if (g->mult_val == const0_rtx)
		*mult_val = const0_rtx;
	      else if (GET_CODE (arg) == CONST_INT && INTVAL (arg) >= 0)
		*mult_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->mult_val)
				       * (1 << INTVAL (arg)));
	      else
		return 0;
	    }
	  else
	    /* Could suceed if arg == 0, but this will never occur.  */
	    return 0;

	  if (GET_CODE (g->add_val) == CONST_INT)
	    {
	      if (g->add_val == const0_rtx)
		*add_val = const0_rtx;
	      else if (GET_CODE (arg) == CONST_INT)
		*add_val = gen_rtx (CONST_INT, VOIDmode,
				       INTVAL (g->add_val)
				       * (1 << INTVAL (arg)));
	      else
		return 0;
	    }
	  else
	    /* Could suceed if arg == 0, but this will never occur.  */
	    return 0;

	  if (subexp)
	    /* G deleted when return, can't return pointer to it.  */
	    return SHIFT_BENEFIT + g->benefit;
	  else
	    {
	      *forces = g;
	      return SHIFT_BENEFIT;
	    }
	}

      if (GET_CODE (arg) == CONST_INT && INTVAL (arg) >= 0)
	*mult_val = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (arg));
      else
	return 0;
      *add_val = const0_rtx;
      return SHIFT_BENEFIT;

      /* These are not worth the trouble.  */
    case ASHIFTRT:
    case LSHIFTRT:
      return 0;

      /* should never reach here */
    default:
      abort ();
      return 0;
    }
}

/* Help detect a giv that is calculated by several consecutive insns;
   for example,
      giv = biv * M
      giv = giv + A
   The caller has already identified the first insn P as having a giv as dest;
   we check that all other insns that set the same register follow
   immediately after P, that they alter nothing else,
   and that the result of the last is still a giv.

   The value is 0 if the reg set in P is not really a giv.
   Otherwise, the value is the amount gained by eliminating
   all the consecutive insns that compute the value.

   FIRST_BENEFIT is the amount gained by eliminating the first insn, P.
   SRC_REGNO is the regno of the biv; DEST_REGNO is that of the giv.

   The coefficients of the ultimate giv value are stored in
   *MULT_VAL and *ADD_VAL.  */

static int
consec_sets_giv (first_benefit, p, src_regno, dest_regno,
		 add_val, mult_val)
     int first_benefit;
     rtx p;
     int src_regno;
     int dest_regno;
     rtx *add_val;
     rtx *mult_val;
{
  int count;
  int benefit = first_benefit;
  enum rtx_code code;
  rtx forces, forces2;
  rtx temp;
  int tem;

  /* Initialize info used by general_induction_var.  */
  struct induction *v =
    (struct induction *) oballoc (sizeof (struct induction));
  v->src_regno = src_regno;
  v->mult_val = *mult_val;
  v->add_val = *add_val;

  induct_var[dest_regno] = GENERAL_INDUCT;
  induct_struct[dest_regno] = v;

  count = n_times_set[dest_regno] - 1;

  while (count > 0)
    {
      p = NEXT_INSN (p);
      code = GET_CODE (p);

      /* If libcall, skip to end of call sequence.  */
      if (code == INSN && (temp = find_reg_note (p, REG_LIBCALL, 0)))
	p = XEXP (temp, 0);

      if (code == INSN && GET_CODE (PATTERN (p)) == SET
	  && GET_CODE (SET_DEST (PATTERN (p))) == REG
	  && REGNO (SET_DEST (PATTERN (p))) == dest_regno
	  && ((tem = general_induction_var (SET_SRC (PATTERN (p)), &src_regno,
					    add_val, mult_val,
					    &forces, &forces2))
	      /* Giv created by call to library routine.  */
	      || ((temp = find_reg_note (p, REG_EQUAL, 0)) &&
		  (tem = general_induction_var (XEXP (temp, 0), &src_regno,
						add_val, mult_val,
						&forces, &forces2))))
	  && src_regno == v->src_regno)
	{
	  count--;
	  benefit += tem;
	  v->mult_val = *mult_val;
	  v->add_val = *add_val;
	}
      else if (code != NOTE)
	{
	  induct_var[dest_regno] = UNKNOWN_INDUCT;
	  return 0;
	}
    }

  return benefit;
}

/* Generate a SEQUENCE to multiply OP0 and OP1 with result in TARGET.
   Use expand_mult to "optimally" do the multiply.
   This also works for machines that do not have multiply insns.
   If one of the operands is a constant, it must be the second.  */

static rtx
gen_iv_mult (mode, op0, op1, target)
     enum machine_mode mode;
     register rtx op0, op1, target;
{
  extern rtx gen_sequence ();
  extern rtx start_sequence ();
  rtx saved, result, temp;

  saved = start_sequence ();

  /* ??? It is very unmodular to use expand_mult here!
     This should be redesigned.  */

  /* UNSIGNEDP arg can be zero since operands/target always same width.  */
  temp = expand_mult (mode, op0, op1, target, 0);

  /* Move to target register, if expand_mult did not put it there.  */
  if (target != 0 && temp != target)
    emit_move_insn (target, temp);

  result = gen_sequence ();
  end_sequence (saved);

  return result;
}

/* Emit code to initialize an induction variable created by strength
   reduction.  */

/* This is necessarily long and messy because cse has already been done,
   so we have to be careful to generate near optimal code for the sequence
   reg = b * m;
   reg += a
 */

static void
emit_iv_init_code (b, m, a, reg, loop_start)
     rtx b;          /* initial value of basic induction variable */
     rtx m;          /* multiplicative constant */
     rtx a;          /* additive constant */
     rtx reg;        /* destination register */
     rtx loop_start;
{
  /* Indicates which of B/M/A are constants.  */
  int status = 0;
  int const_val;
  rtx tmp;

  if (GET_CODE (b) == CONST_INT)
    status |= 0x1;
  if (GET_CODE (m) == CONST_INT)
    status |= 0x2;
  if (GET_CODE (a) == CONST_INT)
    status |= 0x4;

  switch (status)
    {
    case 0:  /* nothing constant */
    case 4:  /* A constant */
      emit_insn_before (gen_iv_mult (GET_MODE (reg), b, m, reg), loop_start);
      /* Don't emit add unless it is necessary.  */
      if (a != const0_rtx)
	emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				   gen_rtx (PLUS, GET_MODE (reg), reg, a)),
			  loop_start);
      break;

    case 1:  /* B constant */
      /* Equivalent to state 2, just need to switch values of B and M
	 and fall through.  */
    case 5:  /* B, a constant */
      /* Equivalent to state 6, just need to switch values of B and M
	 and fall through.  */
      tmp = b;
      b = m;
      m = tmp;

    case 2:  /* M constant */
    case 6:  /* M, A constant */
      const_val = INTVAL (m);
      if (const_val == 0)
	/* REG = A */
	emit_insn_before (gen_rtx (SET, VOIDmode, reg, a),
			  loop_start);
      else if (const_val == 1)
	{
	  /* REG = A + B */
	  if (a != const0_rtx)
	    emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				       gen_rtx (PLUS, GET_MODE (reg), b, a)),
			      loop_start);
	  else
	    emit_insn_before (gen_rtx (SET, VOIDmode, reg, b), loop_start);
	}
      else if (const_val == -1)
	{
	  /* REG = A - B */
	  if (a != const0_rtx)
	    emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				       gen_rtx (MINUS, GET_MODE (reg), a, b)),
			      loop_start);
	  else
	    emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				       gen_rtx (NEG, GET_MODE (reg), b)),
			      loop_start);
	}
      else
	{
	  /* Must generate a `multiply' instruction.  */
	  emit_insn_before (gen_iv_mult (GET_MODE (reg), b, m, reg),
			    loop_start);

	  if (a != const0_rtx)
	    emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				       gen_rtx (PLUS, GET_MODE (reg), reg, a)),
			      loop_start);
	}
      break;

    case 3:  /* B, M constant */
      const_val = INTVAL (b) * INTVAL (m);
      if (const_val == 0)
	emit_insn_before (gen_rtx (SET, VOIDmode, reg, a),
			  loop_start);
      else
	emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				   gen_rtx (PLUS, GET_MODE (reg),
					    gen_rtx (CONST_INT, VOIDmode,
						     const_val),
					    a)),
			loop_start);
      break;

    case 7:  /* all are constant */
      emit_insn_before (gen_rtx (SET, VOIDmode, reg,
			  gen_rtx (CONST_INT, VOIDmode,
				   INTVAL (b) * INTVAL (m) + INTVAL (a))),
		 loop_start);
      break;

    default:
      abort ();
    }
}

/* Test whethen BIV_ADD * GIV_MULT can be computed without
   an actual multiply insn.  Value is 1 if so.  */

static int
product_cheap_p (biv_add, giv_mult)
     rtx biv_add;
     rtx giv_mult;
{
  /* Indicates which of MULT/ADD are constants.  */
  int status = 0;
  int const_val;
  rtx tmp;

  if (GET_CODE (biv_add) == CONST_INT)
    status |= 0x1;
  if (GET_CODE (giv_mult) == CONST_INT)
    status |= 0x2;

  switch (status)
    {
    case 0:
      /* Neither is constant: would need a multiply insn, so fail.  */
      return 0;

    case 1:
      /* BIV_ADD value is constant */
      /* Equivalent to state 2, just switch values of BIV_ADD and GIV_MULT
	 and fall through.  */
      tmp = biv_add;
      biv_add = giv_mult;
      giv_mult = tmp;

    case 2:
      /* GIV_MULT value is constant.
	 If it is 1, 0 or -1 then we win.  */
      const_val = INTVAL (giv_mult);
      if (const_val < -1 || const_val > 1)
	{
	  tmp = gen_iv_mult (GET_MODE (biv_add), biv_add, giv_mult, 0);
	  /* Don't emit a multiply insn, just fail instead.  */
	  if ((GET_CODE (tmp) == SET && GET_CODE (SET_SRC (tmp)) == MULT)
	         /* Also fail if library call (which generates more
		    then two insn) is needed.  */
	      || (GET_CODE (tmp) == SEQUENCE && XVECLEN (tmp, 0) > 2))
	    return 0;
	}
      return 1;

    case 3:
      /* Both BIV_ADD and GIV_MULT are constant;
	 can compute the product at compile time.  */
      return 1;

    default:
      abort ();
    }
}


/* Emit code to increment the induction variable inside the loop.
   Try to emit optimal code for the expression
   REG = REG + BIV_ADD * GIV_MULT.  */

static void
emit_iv_inc (biv_add, giv_mult, reg, insn)
     rtx biv_add;                   /* increment value for biv */
     rtx giv_mult;                  /* multiply value of giv */
     rtx reg;                       /* create insn to set this reg */
     rtx insn;                      /* where to insert the new insn */
{
  /* Indicates which of MULT/ADD are constants.  */
  int status = 0;
  int const_val;
  rtx tmp, tempreg;
  enum machine_mode mode = GET_MODE (reg);

  if (GET_CODE (biv_add) == CONST_INT)
    status |= 0x1;
  if (GET_CODE (giv_mult) == CONST_INT)
    status |= 0x2;

  switch (status)
    {
    case 1:
      /* BIV_ADD value is constant */
      /* Equivalent to state 2, just switch values of BIV_ADD and GIV_MULT
	 and fall through.  */
      tmp = biv_add;
      biv_add = giv_mult;
      giv_mult = tmp;

    case 2:
      /* GIV_MULT value is constant */
      const_val = INTVAL (giv_mult);
      if (const_val == 0)
	/* No code necessary.  This should be VERY rare.  */
	break;
      else if (const_val == 1)
	{
	  emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				     gen_rtx (PLUS, mode, reg, biv_add)),
			    insn);
	  break;
	}
      else if (const_val == -1)
	{
	  emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				     gen_rtx (MINUS, mode, reg, biv_add)),
			    insn);
	  break;
	}

    case 0:
      /* Variable times variable,
	 or variable times constant (not 0, -1 or 1):
	 emit a real multiply.  */
      tempreg = gen_reg_rtx (mode);
      tmp = gen_iv_mult (mode, biv_add, giv_mult, tempreg);
      emit_insn_before (tmp, insn);
      emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				 gen_rtx (PLUS, mode, reg, tempreg)),
			insn);
      break;

    case 3:
      /* Both BIV_ADD and GIV_MULT are constant */
      emit_insn_before (gen_rtx (SET, VOIDmode, reg,
				 gen_rtx (PLUS, mode, reg,
					  gen_rtx (CONST_INT, VOIDmode,
						   INTVAL (biv_add)
						   * INTVAL (giv_mult)))),
			insn);
      break;

    default:
      abort ();
    }
}

/* Check to see if loop can be terminated by a "decrement and branch until
   zero" instruction.  If so, add a REG_NONNEG note to the branch insn if so.
   Also try reversing an increment loop to a decrement loop
   to see if the optimization can be performed.
   Value is nonzero if optimization was performed.  */

static int
check_dbra_loop (loop_end, iv_list, insn_count, loop_start)
     rtx loop_end;
     struct iv_class *iv_list;
     int insn_count;
     rtx loop_start;
{
  struct iv_class *bl;
  rtx reg;
  rtx jump_label;
  rtx final_value;
  rtx start_value;
  enum rtx_code branch_code;
  rtx new_add_val;
  rtx tested_before_loop = 0;
  rtx p;

  /* See if the loop is contained in  `if (X >= 0)' for some reg X.
     If so, then we know X is initially nonnegative even though
     we don't know its initial value.
     Record X in TESTED_BEFORE_LOOP.  */

  for (p = loop_start; p != 0; p = PREV_INSN (p))
    if (GET_CODE (p) != NOTE)
      break;

  /* See if a conditional branch preceeds the loop.
     There may be no other insns or labels between it and
     the beginning of the loop.  */
  if (p != 0 && GET_CODE (p) == JUMP_INSN && condjump_p (p)
      && SET_SRC (PATTERN (p)) != pc_rtx
      && ((GET_CODE (XEXP (SET_SRC (PATTERN (p)), 0)) == LT
	   && XEXP (SET_SRC (PATTERN (p)), 2) == pc_rtx)
	  ||
	  (GET_CODE (XEXP (SET_SRC (PATTERN (p)), 0)) == GE
	   && XEXP (SET_SRC (PATTERN (p)), 1) == pc_rtx))
      && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end))
    {
      /* Before the branch should be a test or compare.
	 See if we are comparing something against zero.  */
      p = PREV_INSN (p);
      if (GET_CODE (p) == INSN && GET_CODE (PATTERN (p)) == SET
	  && SET_DEST (PATTERN (p)) == cc0_rtx)
	{
	  if (GET_CODE (SET_SRC (PATTERN (p))) == REG)
	    tested_before_loop = SET_SRC (PATTERN (p));
	  else if (GET_CODE (SET_SRC (PATTERN (p))) == MINUS
		   && GET_CODE (XEXP (SET_SRC (PATTERN (p)), 1)) == REG
		   && XEXP (SET_SRC (PATTERN (p)), 1) == const0_rtx)
	    tested_before_loop = XEXP (SET_SRC (PATTERN (p)), 0);
	}
    }

  /* If last insn is a conditional branch, and the insn before tests a register
     value, then try to optimize it.  */

  if (GET_CODE (PREV_INSN (loop_end)) == JUMP_INSN
      && GET_CODE (PATTERN (PREV_INSN (loop_end))) == SET
      && GET_CODE (SET_SRC (PATTERN (PREV_INSN (loop_end)))) == IF_THEN_ELSE
      && GET_CODE (PREV_INSN (PREV_INSN (loop_end))) == INSN
      && GET_CODE (PATTERN (PREV_INSN (PREV_INSN (loop_end)))) == SET
      && (GET_CODE (SET_DEST (PATTERN (PREV_INSN (PREV_INSN (loop_end))))) ==
	  CC0))
    {
      /* Check all of the bivs to see if the compare uses one of them.  */

      for (bl = iv_list; bl; bl = bl->next)
	{
	  if (reg_mentioned_p (SET_DEST (PATTERN (bl->biv->insn)),
			       PREV_INSN (PREV_INSN (loop_end))))
	    break;
	}

      /* If biv set more than once, then give up.
	 We can't guarantee that it will be zero on the last iteration.  */
      if (bl && bl->biv_count == 1)
	{
	  /* Look for the case where the basic induction variable is always
	     nonnegative, and equals zero on the last iteration.
	     In this case, add a reg_note REG_NONNEG, which allows the
	     m68k DBRA instruction to be used.  */

	  /* the decrement case */

	  if (GET_CODE (bl->biv->add_val) == CONST_INT
	      && INTVAL (bl->biv->add_val) < 0)
	    {
	      /* Initial value must be greater than 0,
		 init_val % -dec_value == 0 to ensure that it equals zero on
		    the last iteration */

	      if (GET_CODE (bl->initial_value) == CONST_INT
		  && INTVAL (bl->initial_value) > 0
		  && (INTVAL (bl->initial_value) %
		      (-INTVAL (bl->biv->add_val))) == 0)
		{
		  /* register always nonnegative, add REG_NOTE to branch */
		  REG_NOTES (PREV_INSN (loop_end))
		    = gen_rtx (EXPR_LIST, REG_NONNEG, 0,
			       REG_NOTES (PREV_INSN (loop_end)));
		  bl->nonneg = 1;

		  return 1;
		}

	      /* If the decrement is 1 and the value was tested as >= 0 before
		 the loop, then we can safely optimize.  */
	      if (SET_DEST (PATTERN (bl->biv->insn)) == tested_before_loop
		  && INTVAL (bl->biv->add_val) == -1)
		{
		  REG_NOTES (PREV_INSN (loop_end))
		    = gen_rtx (EXPR_LIST, REG_NONNEG, 0,
			       REG_NOTES (PREV_INSN (loop_end)));
		  bl->nonneg = 1;

		  return 1;
		}
	    }
	  else
	    {
	      /* Try to change inc to dec, so can apply above optimization.  */
	      /* Can do this if:
		 all registers modified are induction variables or invariant,
		 all memory references have non-overlapping addresses
                       (obviously true if only one write)
	         allow 2 insns for the compare/jump at the end of the loop.  */

	      /* This code only acts for innermost loops.  Also it simplifies
		 the memory address check by only reversing loops with
		 zero or one memory access.  */

	      if (num_mem_sets <= 1
		  && !loop_has_call
		  && (bl->giv_count + bl->biv_count + num_mem_sets
		      + num_movables + 2 == insn_count))
		{
		  rtx src_two_before_end;

		  /* Loop can be reversed.  */
		  if (loop_dump_stream)
		    fprintf (loop_dump_stream, "Can reverse loop\n");

		  /* Now check other conditions:
		     initial_value must be zero,
		     final_value % add_val == 0, so that when reversed, the
		     biv will be zero on the last iteration.  */

		  /* Calculating the final value non trivial.
		     If branch is (LT (CC0) (CONST 0),
		     then value in compare is final value.
		     If branch is (LE (CC0) (CONST 0),
		     then value in compare is final_value - add_val */

		  branch_code
		    = GET_CODE (XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 0));
		  src_two_before_end
		    = PATTERN (PREV_INSN (PREV_INSN (loop_end)));

		  if (bl->initial_value == const0_rtx
		      && (branch_code == LT || branch_code == LE)
		      && XEXP (XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 0), 1) == const0_rtx
		      && GET_CODE (XEXP (src_two_before_end, 1)) == CONST_INT
		      && (INTVAL (XEXP (src_two_before_end, 1)) % INTVAL (bl->biv->add_val)) == 0)
		    {
		      /* Register will always be nonnegative, with value
			 0 on last iteration if loop reversed */

		      /* Save some info needed to produce the new insns.  */
		      reg = SET_DEST (PATTERN (bl->biv->insn));
		      jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
		      new_add_val = gen_rtx (CONST_INT, VOIDmode,
					     - INTVAL (bl->biv->add_val));


		      if (branch_code == LT)
			{
			  final_value = XEXP (src_two_before_end, 1);
			  start_value
			    = gen_rtx (CONST_INT, VOIDmode,
				       (INTVAL (XEXP (src_two_before_end, 1))
					- INTVAL (bl->biv->add_val)));
			}
		      else /* branch_code == LE */
			{
			  start_value = XEXP (src_two_before_end, 1);
			  final_value
			    = gen_rtx (CONST_INT, VOIDmode,
				       (INTVAL (XEXP (src_two_before_end, 1))
					+ INTVAL (bl->biv->add_val)));
			}

		      /* Initialize biv to start_value before loop start.
			 The old initializing insn will be deleted as a
			 dead store by flow.c.  */
		      emit_insn_before (gen_rtx (SET, VOIDmode, reg,
						 start_value),
					loop_start);

		      /* Add insn to decrement register, and delete insn
			 that incremented the register.  */
		      emit_insn_before (gen_rtx (SET, VOIDmode, reg,
					  gen_rtx (PLUS, GET_MODE (reg), reg,
						   new_add_val)),
					bl->biv->insn);
		      /* Update biv info to reflect its new status.  */
		      bl->biv->insn = PREV_INSN (bl->biv->insn);
		      delete_insn (NEXT_INSN (bl->biv->insn));

		      /* Set LABEL_NUSES to two so that delete_insn will
			 not delete the label.  */
		      LABEL_NUSES (XEXP (jump_label, 0)) = 2;

		      if (regno_last_uid[bl->regno] != INSN_UID (PREV_INSN (loop_end)))
			emit_insn_after (gen_rtx (SET, VOIDmode, reg,
						  final_value),
					 loop_end);

		      /* Delete compare/branch at end of loop.  */
		      delete_insn (PREV_INSN (loop_end));
		      delete_insn (PREV_INSN (loop_end));

		      /* Add new compare/branch insn at end of loop.  */
		      emit_insn_before (gen_rtx (SET, VOIDmode, cc0_rtx, reg),
					loop_end);
		      emit_jump_insn_before (gen_rtx (SET, VOIDmode, pc_rtx,
					 gen_rtx (IF_THEN_ELSE, VOIDmode,
					     gen_rtx (GE, VOIDmode, cc0_rtx,
						      const0_rtx),
					     jump_label,
					     pc_rtx)),
					  loop_end);

		      /* Register is now always nonnegative,
			 so add REG_NONNEG note to the branch.  */
		      REG_NOTES (PREV_INSN (loop_end))
			= gen_rtx (EXPR_LIST, REG_NONNEG, 0,
				   REG_NOTES (PREV_INSN (loop_end)));
		      bl->nonneg = 1;

		      /* Update rest of biv info.  */
		      bl->initial_value = start_value;
		      bl->biv->add_val = new_add_val;

		      if (loop_dump_stream)
			fprintf (loop_dump_stream, "Reversed loop and added reg_nonneg\n");

		      return 1;
		    }
		}
	    }
	}
    }
  return 0;
}

/* Return 1 if INSN, a compare insn which tests the biv described by BL,
   can be rewritten to use instead some reduced giv related to that biv.
   Does not change the rtl.

   We make the assumption that all the givs depending on this biv
   will be reduced, since only in that case will an attempt to eliminate
   the biv actually be made.

   The following function is very parallel to this one.  */

static int
can_eliminate_biv_p (insn, bl)
     rtx insn;
     struct iv_class *bl;
{
  rtx src;
  enum rtx_code code;
  struct induction *v, *tv;
  rtx arg;
  int arg_operand;
  /* Mode of this biv.  */
  enum machine_mode mode = GET_MODE (SET_DEST (PATTERN (bl->biv->insn)));

  if (SET_DEST (PATTERN (insn)) != cc0_rtx)
    return 0;

  src = SET_SRC (PATTERN (insn));
  code = GET_CODE (src);

  switch (code)
    {
      /* a test insn */
    case REG:
      /* Can replace with any giv that has (MULT_VAL != 0) and (ADD_VAL == 0)
	 and make sure it was strength reduced by checking for NEW_REG != 0 */

      for (v = bl->giv; v; v = v->family)
	if (v->mult_val != const0_rtx && v->add_val == const0_rtx
	    && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	  return 1;

      /* Look for a giv with (MULT_VAL != 0) and (ADD_VAL != 0);
	 replace test insn with a compare insn (cmp REDUCED_GIV ADD_VAL) */

      for (v = bl->giv; v; v = v->family)
	if (v->mult_val != const0_rtx
	    && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	  return 1;
      return 0;

      /* a compare insn */
    case MINUS:
      /* Figure out which operand is the biv.  */
      if ((GET_CODE (XEXP (src, 0)) == REG)
	  && (REGNO (XEXP (src, 0)) == bl->regno))
	{
	  arg = XEXP (src, 1);
	  arg_operand = 1;
	}
      else
	{
	  arg = XEXP (src, 0);
	  arg_operand = 0;
	}

      if (GET_CODE (arg) == CONST_INT)
	{
	  /* Can replace with any giv that has constant coefficients.  */

	  for (v = bl->giv; v; v = v->family)
	    if (GET_CODE (v->mult_val) == CONST_INT
		&& GET_CODE (v->add_val) == CONST_INT
		&& GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	      return 1;

	  /* Look for giv with constant mult_val and nonconst add_val,
	     since we can insert add insn before loop
	     to calculate new compare value.  */

	  for (v = bl->giv; v; v = v->family)
	    if (GET_CODE (v->mult_val) == CONST_INT
		&& GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	      return 1;
	}
      else if (GET_CODE (arg) == REG || GET_CODE (arg) == MEM)
	{
	  /* Comparing against invariant register or memref can be handled.  */

	  if (invariant_p (arg))
	    {
	      /* Look for giv with constant mult_val and nonconst add_val.
		 Insert add-insn before loop to compute new compare value.  */

	      for (v = bl->giv; v; v = v->family)
		if ((GET_CODE (v->mult_val) == CONST_INT)
		    && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
		  return 1;
	    }

	  /* Otherwise, only comparing against a biv can be handled.  */
	  if (GET_CODE (arg) != REG
	      || induct_var[REGNO (arg)] != BASIC_INDUCT)
	    return 0;

	  /* Look for a giv for each biv that have identical
	     values for mult_val and add_val.  */
	  for (v = bl->giv; v; v = v->family)
	    if (GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	      {
		for (tv = class_struct[REGNO (arg)]->giv; tv; tv = tv->family)
		  if ((tv->new_reg != 0)
		      && rtx_equal_p (tv->mult_val, v->mult_val)
		      && rtx_equal_p (tv->mult_val, v->mult_val)
		      && GET_MODE (SET_DEST (PATTERN (tv->insn))) == mode)
		    return 1;
	      }
	}
      return 0;

    default:
      return 0;
    }
}

/* Rewrite a compare insn INSN which uses the biv described by BL
   so that it doesn't use that biv any more.
   Instead it will use some reduced giv related to that biv.

   The preceding function is very parallel to this one.  */

static void
eliminate_biv (insn, bl, loop_start)
     rtx insn;
     struct iv_class *bl;
     rtx loop_start;
{
  rtx src = SET_SRC (PATTERN (insn));
  enum rtx_code code = GET_CODE (src);
  struct induction *v, *tv;
  rtx arg;
  int arg_operand;
  /* Mode of this biv.  */
  enum machine_mode mode = GET_MODE (SET_DEST (PATTERN (bl->biv->insn)));

  switch (code)
    {
      /* a test insn */
    case REG:
      /* Can replace with any giv
	 that has (MULT_VAL != 0) and (ADD_VAL == 0).  */

      for (v = bl->giv; v; v = v->family)
	if (v->mult_val != const0_rtx && v->add_val == const0_rtx
	    && v->new_reg != 0
	    && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	  break;
      if (v)
	{
	  /* We can test the sign of that giv's reduced reg.  */
	  SET_SRC (PATTERN (insn)) = v->new_reg;
	  return;
	}

      /* Look for a giv with (MULT_VAL != 0) and (ADD_VAL != 0);
	 replace test insn with a compare insn (cmp REDUCED_GIV ADD_VAL) */

      for (v = bl->giv; v; v = v->family)
	if (v->mult_val != const0_rtx && v->new_reg != 0
	    && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	  break;
      if (v)
	{
	  /* Replace biv with the giv's reduced register.  */
	  SET_SRC (PATTERN (insn)) = gen_rtx (MINUS, GET_MODE (v->new_reg),
					      v->new_reg, v->add_val);

#if 0
	  /* add_val must be invariant, so don't bother storing in a register */
	  /* calculate the appropriate constant to compare against */
	  emit_insn_before (gen_rtx (SET, VOIDmode, compare_value,
				     v->add_val),
			    loop_start);
#endif
	  return;
	}
      abort ();
      break;

      /* a compare insn */
    case MINUS:
      /* Figure out which operand is the biv.  */
      if ((GET_CODE (XEXP (src, 0)) == REG)
	  && (REGNO (XEXP (src, 0)) == bl->regno))
	{
	  arg = XEXP (src, 1);
	  arg_operand = 1;
	}
      else
	{
	  arg = XEXP (src, 0);
	  arg_operand = 0;
	}

      if (GET_CODE (arg) == CONST_INT)
	{
	  /* Can replace with any giv that has constant mult_val and add_val.
	     Make sure it was strength reduced by checking new_reg != 0.  */

	  for (v = bl->giv; v; v = v->family)
	    if (GET_CODE (v->mult_val) == CONST_INT
		&& GET_CODE (v->add_val) == CONST_INT
		&& v->new_reg
		&& GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	      break;
	  if (v)
	    {
	      /* Replace biv with the giv's reduced reg.  */
	      XEXP (src, 1-arg_operand) = v->new_reg;
	      /* Calculate the appropriate constant to compare against.  */
	      XEXP (src, arg_operand) = gen_rtx (CONST_INT, VOIDmode,
					 (INTVAL (arg) * INTVAL (v->mult_val)
					         + INTVAL (v->add_val)));
	      return;
	    }

	  /* Look for giv with constant mult_val and nonconst add_val.
	     Insert add insn before loop to calculate new compare value.  */

	  for (v = bl->giv; v; v = v->family)
	    if (GET_CODE (v->mult_val) == CONST_INT
		&& v->new_reg
		&& GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
	      break;
	  if (v)
	    {
	      rtx compare_value = gen_reg_rtx (mode);

	      /* Replace biv with giv's reduced register.  */
	      XEXP (src, 1-arg_operand) = v->new_reg;

	      /* At start of loop, compute value to compare against.  */
	      emit_insn_before (gen_rtx (SET, VOIDmode, compare_value,
				  gen_rtx (PLUS, mode, v->add_val,
				     gen_rtx (CONST_INT, VOIDmode,
					INTVAL (arg) * INTVAL (v->mult_val)))),
				loop_start);
	      XEXP (src, arg_operand) = compare_value;
	      return;
	    }
	  abort ();
	}
      else if (GET_CODE (arg) == REG || GET_CODE (arg) == MEM)
	{
	  if (invariant_p (arg))
	    {
	      /* Look for giv with constant mult_val and nonconst add_val.
		 Insert add-insn before loop to compute new compare value.  */

	      for (v = bl->giv; v; v = v->family)
		if (GET_CODE (v->mult_val) == CONST_INT
		    && v->new_reg
		    && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
		  break;
	      if (v)
		{
		  rtx compare_value = gen_reg_rtx (mode);

		  /* Replace biv with giv's reduced register.  */
		  XEXP (src, 1-arg_operand) = v->new_reg;

		  /* Calculate the appropriate constant to compare against.  */
		  emit_insn_before (gen_iv_mult (mode, arg, v->mult_val,
						 compare_value),
				    loop_start);
		  emit_insn_before (gen_rtx (SET, VOIDmode, compare_value,
					     gen_rtx (PLUS, mode, v->add_val,
						      compare_value)),
				    loop_start);
		  XEXP (src, arg_operand) = compare_value;
		  return;
		}
	    }

	  /* Otherwise the reg compared with had better be a biv.  */
	  if (GET_CODE (arg) != REG
	      || induct_var[REGNO (arg)] != BASIC_INDUCT)
	    abort ();

	  /* Look for a pair of givs, one for each biv,
	     with identical coefficients.  */
	  for (v = bl->giv; v; v = v->family)
	    {
	      if (!v->new_reg
		  && GET_MODE (SET_DEST (PATTERN (v->insn))) == mode)
		continue;
	      for (tv = class_struct[REGNO (arg)]->giv; tv; tv = tv->family)
		if ((tv->new_reg != 0)
		    && rtx_equal_p (tv->mult_val, v->mult_val)
		    && rtx_equal_p (tv->mult_val, v->mult_val)
		    && GET_MODE (SET_DEST (PATTERN (tv->insn))) == mode)
		  break;
	      if (tv)
		break;
	    }
	  if (v)
	    {
	      /* Replace biv with its giv's reduced reg.  */
	      XEXP (src, 1-arg_operand) = v->new_reg;
	      /* Replace other operand with the other giv's reduced reg.  */
	      XEXP (src, arg_operand) = tv->new_reg;
	      return;
	    }
	}
      abort ();

    default:
      abort ();
    }
}

/* Try to calculate the final value of the biv,
   the value it will have at the end of the loop.
   If we can do it, return that value.  */

/* ??? One case that should be simple to handle
   is when the biv is incremented by an invariant
   exactly once each time around the loop,
   and when the number of iterations can be determined
   (as the value of some invariant).
   Then the final value would be BIV + (INCREMENT * NUM_ITERATIONS).

   Once that case is handled, it would become desirable to detect empty
   loops and delete them, since this optimization could make empty loops.  */

static rtx
final_biv_value (bl, loop_end)
     struct iv_class *bl;
     rtx loop_end;
{
  /* wimpy, but guaranteed to work */
  return 0;
}
