This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Merge rtl iv analysis changes from killloop-branch


Hello,

this patch merges changes to rtl iv analysis from killloop branch.  Most
importantly, iv analysis now uses UD chains from df.c, instead of
the simple own implementation it used before.  In addition to being
a cleanup, it also makes the iv analysis more powerful.

The change to optabs.c is described in
http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00900.html.

Bootstrapped & regtested on i686, ia65 and ppc64.

Zdenek

	* loop-iv.c: Include df.h and hashtab.h.
	(enum iv_grd_result): New enum.
	(DF_REF_IV, DF_REF_IV_SET): New macros.
	(struct biv_entry): New.
	(df, bivs): New global variables.
	(struct insn_info, insn_info, last_def, bivs, max_insn_no, max_reg_no,
	assign_luids, mark_sets, kill_sets, mark_single_set, simple_set_p):
	Removed.
	(clear_iv_info, latch_dominating_def, record_iv, iv_analyze_expr,
	iv_analyze_result, iv_analyze_def, biv_hash, biv_eq,
	analyzed_for_bivness_p, record_biv): New functions.
	(iv_analysis_loop_init, iv_get_reaching_def, simple_reg_p,
	get_biv_step_1, get_biv_step, iv_analyze_biv, iv_analyze_op,
	iv_analyze, biv_p, iv_analysis_done): Work with df representation of
	UD chains.
	(iv_constant, iv_subreg, iv_extend, iv_mult, iv_shift): Do not set
	analysed.
	(iv_number_of_iterations): Use new interface to iv analysis.
	* loop-unroll.c: Do not include varray.h.
	(analyze_iv_to_split_insn): Use new interface to iv
	analysis.
	* loop-unswitch.c (may_unswitch_on): Ditto.
	* df.c (df_bitmaps_free): Only work for bbs for that structures are
	allocated.
	(df_bb_modify): Realloc tables to the new index.
	(df_find_use): New function.
	* df.h (df_find_use): Declare.
	* optabs.c (expand_unop): Make the mode of the REG_EQUAL node be
	outmode.
	* cfgloop.h (struct rtx_iv): Remove analysed field.
	(iv_get_reaching_def): Removed.
	(iv_analyze_result, iv_analyze_expr, iv_current_loop_df): Declare.
	* Makefile.in (loop-unroll.o): Remove VARRAY_H dependency.
	(loop-iv.o): Add df.h and hashtab.h dependency.

Index: loop-unswitch.c
===================================================================
*** loop-unswitch.c	(revision 107537)
--- loop-unswitch.c	(working copy)
*************** unswitch_loops (struct loops *loops)
*** 172,178 ****
  static rtx
  may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
  {
!   rtx test, at, insn, op[2], stest;
    struct rtx_iv iv;
    unsigned i;
    enum machine_mode mode;
--- 172,178 ----
  static rtx
  may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
  {
!   rtx test, at, op[2], stest;
    struct rtx_iv iv;
    unsigned i;
    enum machine_mode mode;
*************** may_unswitch_on (basic_block bb, struct 
*** 205,212 ****
        if (CONSTANT_P (op[i]))
  	continue;
  
!       insn = iv_get_reaching_def (at, op[i]);
!       if (!iv_analyze (insn, op[i], &iv))
  	return NULL_RTX;
        if (iv.step != const0_rtx
  	  || iv.first_special)
--- 205,211 ----
        if (CONSTANT_P (op[i]))
  	continue;
  
!       if (!iv_analyze (at, op[i], &iv))
  	return NULL_RTX;
        if (iv.step != const0_rtx
  	  || iv.first_special)
Index: optabs.c
===================================================================
*** optabs.c	(revision 107537)
--- optabs.c	(working copy)
*************** expand_unop (enum machine_mode mode, opt
*** 2570,2576 ****
  
        target = gen_reg_rtx (outmode);
        emit_libcall_block (insns, target, value,
! 			  gen_rtx_fmt_e (unoptab->code, mode, op0));
  
        return target;
      }
--- 2570,2576 ----
  
        target = gen_reg_rtx (outmode);
        emit_libcall_block (insns, target, value,
! 			  gen_rtx_fmt_e (unoptab->code, outmode, op0));
  
        return target;
      }
Index: df.c
===================================================================
*** df.c	(revision 107537)
--- df.c	(working copy)
*************** df_bitmaps_alloc (struct df *df, bitmap 
*** 451,464 ****
  static void
  df_bitmaps_free (struct df *df, int flags)
  {
!   basic_block bb;
! 
!   FOR_EACH_BB (bb)
      {
!       struct bb_info *bb_info = DF_BB_INFO (df, bb);
! 
!       if (!bb_info)
! 	continue;
  
        if ((flags & DF_RD) && bb_info->rd_in)
  	{
--- 451,461 ----
  static void
  df_bitmaps_free (struct df *df, int flags)
  {
!   unsigned i;
!       
!   for (i = 0; i < df->n_bbs; i++)
      {
!       struct bb_info *bb_info = &df->bbs[i];
  
        if ((flags & DF_RD) && bb_info->rd_in)
  	{
*************** static void
*** 2649,2655 ****
  df_bb_modify (struct df *df, basic_block bb)
  {
    if ((unsigned) bb->index >= df->n_bbs)
!     df_bb_table_realloc (df, df->n_bbs);
  
    bitmap_set_bit (df->bbs_modified, bb->index);
  }
--- 2646,2652 ----
  df_bb_modify (struct df *df, basic_block bb)
  {
    if ((unsigned) bb->index >= df->n_bbs)
!     df_bb_table_realloc (df, bb->index);
  
    bitmap_set_bit (df->bbs_modified, bb->index);
  }
*************** df_find_def (struct df *df, rtx insn, rt
*** 3052,3057 ****
--- 3049,3075 ----
    return NULL;
  }
  
+ /* Finds the reference corresponding to the use of REG in INSN.
+    DF is the dataflow object.  */
+ 
+ struct ref *
+ df_find_use (struct df *df, rtx insn, rtx reg)
+ {
+   struct df_link *uses;
+ 
+   for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
+     {
+       rtx areg = DF_REF_REG (uses->ref);
+       if (GET_CODE (areg) == SUBREG)
+ 	areg = SUBREG_REG (areg);
+ 
+       if (rtx_equal_p (areg, reg))
+ 	return uses->ref;
+     }
+ 
+   return NULL;
+ }
+ 
  /* Return 1 if REG is referenced in INSN, zero otherwise.  */ 
  
  int
Index: df.h
===================================================================
*** df.h	(revision 107537)
--- df.h	(working copy)
*************** extern struct ref *df_bb_regno_last_def_
*** 293,298 ****
--- 293,300 ----
  
  extern struct ref *df_find_def (struct df *, rtx, rtx);
  
+ extern struct ref *df_find_use (struct df *, rtx, rtx);
+ 
  extern int df_reg_used (struct df *, rtx, rtx);
  
  /* Functions for debugging from GDB.  */
Index: loop-unroll.c
===================================================================
*** loop-unroll.c	(revision 107537)
--- loop-unroll.c	(working copy)
*************** Software Foundation, 51 Franklin Street,
*** 33,39 ****
  #include "expr.h"
  #include "hashtab.h"
  #include "recog.h"    
- #include "varray.h"                        
  
  /* This pass performs loop unrolling and peeling.  We only perform these
     optimizations on innermost loops (with single exception) because
--- 33,38 ----
*************** analyze_iv_to_split_insn (rtx insn)
*** 1670,1676 ****
    if (!biv_p (insn, dest))
      return NULL;
  
!   ok = iv_analyze (insn, dest, &iv);
    gcc_assert (ok);
  
    if (iv.step == const0_rtx
--- 1669,1675 ----
    if (!biv_p (insn, dest))
      return NULL;
  
!   ok = iv_analyze_result (insn, dest, &iv);
    gcc_assert (ok);
  
    if (iv.step == const0_rtx
Index: loop-iv.c
===================================================================
*** loop-iv.c	(revision 107537)
--- loop-iv.c	(working copy)
*************** along with GCC; see the file COPYING.  I
*** 18,47 ****
  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.  */
  
! /* This is just a very simplistic analysis of induction variables of the loop.
!    The major use is for determining the number of iterations of a loop for
!    loop unrolling, doloop optimization and branch prediction.  For this we
!    are only interested in bivs and a fairly limited set of givs that are
!    needed in the exit condition.  We also only compute the iv information on
!    demand.
! 
!    The interesting registers are determined.  A register is interesting if
! 
!    -- it is set only in the blocks that dominate the latch of the current loop
!    -- all its sets are simple -- i.e. in the form we understand
! 
!    We also number the insns sequentially in each basic block.  For a use of the
!    interesting reg, it is now easy to find a reaching definition (there may be
!    only one).
  
!    Induction variable is then simply analyzed by walking the use-def
!    chains.
     
!    Usage:
  
     iv_analysis_loop_init (loop);
!    insn = iv_get_reaching_def (where, reg);
!    if (iv_analyze (insn, reg, &iv))
       {
         ...
       }
--- 18,34 ----
  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.  */
  
! /* This is a simple analysis of induction variables of the loop.  The major use
!    is for determining the number of iterations of a loop for loop unrolling,
!    doloop optimization and branch prediction.  The iv information is computed
!    on demand.
  
!    Induction variable is analyzed by walking the use-def chains.
     
!    Usage (REG must be used in WHERE):
  
     iv_analysis_loop_init (loop);
!    if (iv_analyze (where, reg, &iv))
       {
         ...
       }
*************** Software Foundation, 51 Franklin Street,
*** 60,99 ****
  #include "intl.h"
  #include "output.h"
  #include "toplev.h"
  
! /* The insn information.  */
  
! struct insn_info
  {
!   /* Id of the insn.  */
!   unsigned luid;
  
!   /* The previous definition of the register defined by the single
!      set in the insn.  */
!   rtx prev_def;
  
!   /* The description of the iv.  */
!   struct rtx_iv iv;
  };
  
! static struct insn_info *insn_info;
  
! /* The last definition of register.  */
  
! static rtx *last_def;
  
! /* The bivs.  */
  
! static struct rtx_iv *bivs;
  
! /* Maximal insn number for that there is place in insn_info array.  */
  
! static unsigned max_insn_no;
  
! /* Maximal register number for that there is place in bivs and last_def
!    arrays.  */
  
! static unsigned max_reg_no;
  
  /* Dumps information about IV to FILE.  */
  
--- 47,107 ----
  #include "intl.h"
  #include "output.h"
  #include "toplev.h"
+ #include "df.h"
+ #include "hashtab.h"
  
! /* Possible return values of iv_get_reaching_def.  */
  
! enum iv_grd_result
  {
!   /* More than one reaching def, or reaching def that does not
!      dominate the use.  */
!   GRD_INVALID,
  
!   /* The use is trivial invariant of the loop, i.e. is not changed
!      inside the loop.  */
!   GRD_INVARIANT,
  
!   /* The use is reached by initial value and a value from the
!      previous iteration.  */
!   GRD_MAYBE_BIV,
! 
!   /* The use has single dominating def.  */
!   GRD_SINGLE_DOM
! };
! 
! /* Information about a biv.  */
! 
! struct biv_entry
! {
!   unsigned regno;	/* The register of the biv.  */
!   struct rtx_iv iv;	/* Value of the biv.  */
  };
  
! /* Induction variable stored at the reference.  */
! #define DF_REF_IV(REF) ((struct rtx_iv *) DF_REF_DATA (REF))
! #define DF_REF_IV_SET(REF, IV) DF_REF_DATA (REF) = (IV)
  
! /* The current loop.  */
  
! static struct loop *current_loop;
  
! /* Dataflow information for the current loop.  */
  
! static struct df *df;
  
! /* Bivs of the current loop.  */
  
! static htab_t bivs;
  
! /* Return the dataflow object for the current loop.  */
! struct df *
! iv_current_loop_df (void)
! {
!   return df;
! }
  
! static bool iv_analyze_op (rtx, rtx, struct rtx_iv *);
  
  /* Dumps information about IV to FILE.  */
  
*************** dump_iv_info (FILE *file, struct rtx_iv 
*** 139,161 ****
      fprintf (file, " (first special)");
  }
  
- /* Assigns luids to insns in basic block BB.  */
- 
- static void
- assign_luids (basic_block bb)
- {
-   unsigned i = 0, uid;
-   rtx insn;
- 
-   FOR_BB_INSNS (bb, insn)
-     {
-       uid = INSN_UID (insn);
-       insn_info[uid].luid = i++;
-       insn_info[uid].prev_def = NULL_RTX;
-       insn_info[uid].iv.analysed = false;
-     }
- }
- 
  /* Generates a subreg to get the least significant part of EXPR (in mode
     INNER_MODE) to OUTER_MODE.  */
  
--- 147,152 ----
*************** simple_reg_p (rtx reg)
*** 191,321 ****
    if (GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
      return false;
  
-   if (last_def[r] == const0_rtx)
-     return false;
- 
    return true;
  }
  
! /* Checks whether assignment LHS = RHS is simple enough for us to process.  */
  
! static bool
! simple_set_p (rtx lhs, rtx rhs)
  {
!   rtx op0, op1;
! 
!   if (!REG_P (lhs)
!       || !simple_reg_p (lhs))
!     return false;
! 
!   if (CONSTANT_P (rhs))
!     return true;
  
!   switch (GET_CODE (rhs))
      {
!     case SUBREG:
!     case REG:
!       return simple_reg_p (rhs);
! 
!     case SIGN_EXTEND:
!     case ZERO_EXTEND:
!     case NEG:
!       return simple_reg_p (XEXP (rhs, 0));
! 
!     case PLUS:
!     case MINUS:
!     case MULT:
!     case ASHIFT:
!       op0 = XEXP (rhs, 0);
!       op1 = XEXP (rhs, 1);
! 
!       if (!simple_reg_p (op0)
! 	  && !CONSTANT_P (op0))
! 	return false;
! 
!       if (!simple_reg_p (op1)
! 	  && !CONSTANT_P (op1))
! 	return false;
! 
!       if (GET_CODE (rhs) == MULT
! 	  && !CONSTANT_P (op0)
! 	  && !CONSTANT_P (op1))
! 	return false;
! 
!       if (GET_CODE (rhs) == ASHIFT
! 	  && CONSTANT_P (op0))
! 	return false;
! 
!       return true;
  
!     default:
!       return false;
      }
- }
- 
- /* Mark single SET in INSN.  */
- 
- static rtx
- mark_single_set (rtx insn, rtx set)
- {
-   rtx def = SET_DEST (set), src;
-   unsigned regno, uid;
- 
-   src = find_reg_equal_equiv_note (insn);
-   if (src)
-     src = XEXP (src, 0);
-   else
-     src = SET_SRC (set);
- 
-   if (!simple_set_p (SET_DEST (set), src))
-     return NULL_RTX;
- 
-   regno = REGNO (def);
-   uid = INSN_UID (insn);
- 
-   bivs[regno].analysed = false;
-   insn_info[uid].prev_def = last_def[regno];
-   last_def[regno] = insn;
  
!   return def;
  }
  
! /* Invalidate register REG unless it is equal to EXCEPT.  */
  
! static void
! kill_sets (rtx reg, rtx by ATTRIBUTE_UNUSED, void *except)
  {
!   if (GET_CODE (reg) == SUBREG)
!     reg = SUBREG_REG (reg);
!   if (!REG_P (reg))
!     return;
!   if (reg == except)
!     return;
! 
!   last_def[REGNO (reg)] = const0_rtx;
  }
  
! /* Marks sets in basic block BB.  If DOM is true, BB dominates the loop
!    latch.  */
  
! static void
! mark_sets (basic_block bb, bool dom)
  {
!   rtx insn, set, def;
! 
!   FOR_BB_INSNS (bb, insn)
!     {
!       if (!INSN_P (insn))
! 	continue;
! 
!       if (dom
! 	  && (set = single_set (insn)))
! 	def = mark_single_set (insn, set);
!       else
! 	def = NULL_RTX;
! 
!       note_stores (PATTERN (insn), kill_sets, def);
!     }
  }
  
  /* Prepare the data for an induction variable analysis of a LOOP.  */
--- 182,227 ----
    if (GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
      return false;
  
    return true;
  }
  
! /* Clears the information about ivs stored in df.  */
  
! static void
! clear_iv_info (void)
  {
!   unsigned i;
!   struct rtx_iv *iv;
  
!   for (i = 0; i < df->n_defs; i++)
      {
!       if (!df->defs[i])
! 	continue;
  
!       iv = DF_REF_IV (df->defs[i]);
!       if (!iv)
! 	continue;
!       free (iv);
!       DF_REF_IV_SET (df->defs[i], NULL);
      }
  
!   htab_empty (bivs);
  }
  
! /* Returns hash value for biv B.  */
  
! static hashval_t
! biv_hash (const void *b)
  {
!   return ((const struct biv_entry *) b)->regno;
  }
  
! /* Compares biv B and register R.  */
  
! static int
! biv_eq (const void *b, const void *r)
  {
!   return ((const struct biv_entry *) b)->regno == REGNO ((rtx) r);
  }
  
  /* Prepare the data for an induction variable analysis of a LOOP.  */
*************** mark_sets (basic_block bb, bool dom)
*** 323,419 ****
  void
  iv_analysis_loop_init (struct loop *loop)
  {
!   basic_block *body = get_loop_body_in_dom_order (loop);
!   unsigned b;
  
!   if ((unsigned) get_max_uid () >= max_insn_no)
      {
!       /* Add some reserve for insns and registers produced in optimizations.  */
!       max_insn_no = get_max_uid () + 100;
!       if (insn_info)
! 	free (insn_info);
!       insn_info = xmalloc (max_insn_no * sizeof (struct insn_info));
      }
  
!   if ((unsigned) max_reg_num () >= max_reg_no)
      {
!       max_reg_no = max_reg_num () + 100;
!       if (last_def)
! 	free (last_def);
!       last_def = xmalloc (max_reg_no * sizeof (rtx));
!       if (bivs)
! 	free (bivs);
!       bivs = xmalloc (max_reg_no * sizeof (struct rtx_iv));
!     }
  
!   memset (last_def, 0, max_reg_num () * sizeof (rtx));
  
!   for (b = 0; b < loop->num_nodes; b++)
!     {
!       assign_luids (body[b]);
!       mark_sets (body[b], just_once_each_iteration_p (loop, body[b]));
      }
  
    free (body);
  }
  
! /* Gets definition of REG reaching the INSN.  If REG is not simple, const0_rtx
!    is returned.  If INSN is before the first def in the loop, NULL_RTX is
!    returned.  */
  
! rtx
! iv_get_reaching_def (rtx insn, rtx reg)
  {
!   unsigned regno, luid, auid;
!   rtx ainsn;
!   basic_block bb, abb;
  
!   if (GET_CODE (reg) == SUBREG)
      {
!       if (!subreg_lowpart_p (reg))
! 	return const0_rtx;
!       reg = SUBREG_REG (reg);
      }
-   if (!REG_P (reg))
-     return NULL_RTX;
  
!   regno = REGNO (reg);
!   if (!last_def[regno]
!       || last_def[regno] == const0_rtx)
!     return last_def[regno];
  
!   bb = BLOCK_FOR_INSN (insn);
!   luid = insn_info[INSN_UID (insn)].luid;
  
!   ainsn = last_def[regno];
!   while (1)
!     {
!       abb = BLOCK_FOR_INSN (ainsn);
  
!       if (dominated_by_p (CDI_DOMINATORS, bb, abb))
! 	break;
  
!       auid = INSN_UID (ainsn);
!       ainsn = insn_info[auid].prev_def;
  
!       if (!ainsn)
! 	return NULL_RTX;
!     }
  
!   while (1)
      {
!       abb = BLOCK_FOR_INSN (ainsn);
!       if (abb != bb)
! 	return ainsn;
! 
!       auid = INSN_UID (ainsn);
!       if (luid > insn_info[auid].luid)
! 	return ainsn;
! 
!       ainsn = insn_info[auid].prev_def;
!       if (!ainsn)
! 	return NULL_RTX;
      }
  }
  
  /* Sets IV to invariant CST in MODE.  Always returns true (just for
--- 229,361 ----
  void
  iv_analysis_loop_init (struct loop *loop)
  {
!   basic_block *body = get_loop_body_in_dom_order (loop), bb;
!   bitmap blocks = BITMAP_ALLOC (NULL);
!   unsigned i;
!   rtx insn;
!   bool first_time = (df == NULL);
  
!   current_loop = loop;
! 
!   /* Clear the information from the analysis of the previous loop.  */
!   if (first_time)
      {
!       df = df_init ();
!       bivs = htab_create (10, biv_hash, biv_eq, free);
      }
+   else
+     clear_iv_info ();
  
!   for (i = 0; i < loop->num_nodes; i++)
      {
!       bb = body[i];
!       bitmap_set_bit (blocks, bb->index);
  
!       if (first_time)
! 	continue;
  
!       /* Mark everything in the body of the loop as modified, since this may be
! 	 the case, and we do not keep track of what changes.  */
!       FOR_BB_INSNS (bb, insn)
! 	{
! 	  df_insn_modify (df, bb, insn);
! 	}
      }
  
+   df_analyze_subcfg (df, blocks, DF_UD_CHAIN
+ 				 | DF_RD_CHAIN
+ 				 | DF_RU_CHAIN
+ 				 | DF_HARD_REGS
+ 				 | DF_EQUIV_NOTES);
+ 
+   BITMAP_FREE (blocks);
    free (body);
  }
  
! /* Finds the definition of REG that dominates loop latch and stores
!    it to DEF.  Returns false if there is not a single definition
!    dominating the latch.  If REG has no definition in loop, DEF
!    is set to NULL and true is returned.  */
  
! static bool
! latch_dominating_def (rtx reg, struct ref **def)
  {
!   struct ref *single_rd = NULL, *adef;
!   struct df_link *def_link;
!   unsigned regno = REGNO (reg);
!   struct bb_info *bb_info = DF_BB_INFO (df, current_loop->latch);
  
!   for (def_link = df->regs[regno].defs; def_link; def_link = def_link->next)
      {
!       adef = def_link->ref;
! 
!       if (!bitmap_bit_p (bb_info->rd_out, DF_REF_ID (adef)))
! 	continue;
! 
!       /* More than one reaching definition.  */
!       if (single_rd)
! 	return false;
! 
!       if (!just_once_each_iteration_p (current_loop, DF_REF_BB (adef)))
! 	return false;
! 
!       single_rd = adef;
      }
  
!   *def = single_rd;
!   return true;
! }
! 
! /* Gets definition of REG reaching its use in INSN and stores it to DEF.  */
  
! static enum iv_grd_result
! iv_get_reaching_def (rtx insn, rtx reg, struct ref **def)
! {
!   struct ref *use, *adef;
!   basic_block def_bb, use_bb;
!   rtx def_insn;
!   bool dom_p;
!   
!   *def = NULL;
!   if (!simple_reg_p (reg))
!     return GRD_INVALID;
!   if (GET_CODE (reg) == SUBREG)
!     reg = SUBREG_REG (reg);
!   gcc_assert (REG_P (reg));
  
!   use = df_find_use (df, insn, reg);
!   gcc_assert (use != NULL);
  
!   if (!DF_REF_CHAIN (use))
!     return GRD_INVARIANT;
  
!   /* More than one reaching def.  */
!   if (DF_REF_CHAIN (use)->next)
!     return GRD_INVALID;
  
!   adef = DF_REF_CHAIN (use)->ref;
!   def_insn = DF_REF_INSN (adef);
!   def_bb = DF_REF_BB (adef);
!   use_bb = BLOCK_FOR_INSN (insn);
  
!   if (use_bb == def_bb)
!     dom_p = (DF_INSN_LUID (df, def_insn) < DF_INSN_LUID (df, insn));
!   else
!     dom_p = dominated_by_p (CDI_DOMINATORS, use_bb, def_bb);
! 
!   if (dom_p)
      {
!       *def = adef;
!       return GRD_SINGLE_DOM;
      }
+ 
+   /* The definition does not dominate the use.  This is still OK if
+      this may be a use of a biv, i.e. if the def_bb dominates loop
+      latch.  */
+   if (just_once_each_iteration_p (current_loop, def_bb))
+     return GRD_MAYBE_BIV;
+ 
+   return GRD_INVALID;
  }
  
  /* Sets IV to invariant CST in MODE.  Always returns true (just for
*************** iv_constant (struct rtx_iv *iv, rtx cst,
*** 425,431 ****
    if (mode == VOIDmode)
      mode = GET_MODE (cst);
  
-   iv->analysed = true;
    iv->mode = mode;
    iv->base = cst;
    iv->step = const0_rtx;
--- 367,372 ----
*************** iv_shift (struct rtx_iv *iv, rtx mby)
*** 653,672 ****
  }
  
  /* The recursive part of get_biv_step.  Gets the value of the single value
!    defined in INSN wrto initial value of REG inside loop, in shape described
     at get_biv_step.  */
  
  static bool
! get_biv_step_1 (rtx insn, rtx reg,
  		rtx *inner_step, enum machine_mode *inner_mode,
  		enum rtx_code *extend, enum machine_mode outer_mode,
  		rtx *outer_step)
  {
    rtx set, rhs, op0 = NULL_RTX, op1 = NULL_RTX;
!   rtx next, nextr, def_insn, tmp;
    enum rtx_code code;
  
    set = single_set (insn);
    rhs = find_reg_equal_equiv_note (insn);
    if (rhs)
      rhs = XEXP (rhs, 0);
--- 594,619 ----
  }
  
  /* The recursive part of get_biv_step.  Gets the value of the single value
!    defined by DEF wrto initial value of REG inside loop, in shape described
     at get_biv_step.  */
  
  static bool
! get_biv_step_1 (struct ref *def, rtx reg,
  		rtx *inner_step, enum machine_mode *inner_mode,
  		enum rtx_code *extend, enum machine_mode outer_mode,
  		rtx *outer_step)
  {
    rtx set, rhs, op0 = NULL_RTX, op1 = NULL_RTX;
!   rtx next, nextr, tmp;
    enum rtx_code code;
+   rtx insn = DF_REF_INSN (def);
+   struct ref *next_def;
+   enum iv_grd_result res;
  
    set = single_set (insn);
+   if (!set)
+     return false;
+ 
    rhs = find_reg_equal_equiv_note (insn);
    if (rhs)
      rhs = XEXP (rhs, 0);
*************** get_biv_step_1 (rtx insn, rtx reg,
*** 742,752 ****
    else
      nextr = next;
  
!   def_insn = iv_get_reaching_def (insn, nextr);
!   if (def_insn == const0_rtx)
      return false;
  
!   if (!def_insn)
      {
        if (!rtx_equal_p (nextr, reg))
  	return false;
--- 689,700 ----
    else
      nextr = next;
  
!   res = iv_get_reaching_def (insn, nextr, &next_def);
! 
!   if (res == GRD_INVALID || res == GRD_INVARIANT)
      return false;
  
!   if (res == GRD_MAYBE_BIV)
      {
        if (!rtx_equal_p (nextr, reg))
  	return false;
*************** get_biv_step_1 (rtx insn, rtx reg,
*** 756,762 ****
        *inner_mode = outer_mode;
        *outer_step = const0_rtx;
      }
!   else if (!get_biv_step_1 (def_insn, reg,
  			    inner_step, inner_mode, extend, outer_mode,
  			    outer_step))
      return false;
--- 704,710 ----
        *inner_mode = outer_mode;
        *outer_step = const0_rtx;
      }
!   else if (!get_biv_step_1 (next_def, reg,
  			    inner_step, inner_mode, extend, outer_mode,
  			    outer_step))
      return false;
*************** get_biv_step_1 (rtx insn, rtx reg,
*** 803,809 ****
        break;
  
      default:
!       gcc_unreachable ();
      }
  
    return true;
--- 751,757 ----
        break;
  
      default:
!       return false;
      }
  
    return true;
*************** get_biv_step_1 (rtx insn, rtx reg,
*** 813,828 ****
  
     OUTER_STEP + EXTEND_{OUTER_MODE} (SUBREG_{INNER_MODE} (REG + INNER_STEP))
  
!    If the operation cannot be described in this shape, return false.  */
  
  static bool
! get_biv_step (rtx reg, rtx *inner_step, enum machine_mode *inner_mode,
! 	      enum rtx_code *extend, enum machine_mode *outer_mode,
! 	      rtx *outer_step)
  {
    *outer_mode = GET_MODE (reg);
  
!   if (!get_biv_step_1 (last_def[REGNO (reg)], reg,
  		       inner_step, inner_mode, extend, *outer_mode,
  		       outer_step))
      return false;
--- 761,777 ----
  
     OUTER_STEP + EXTEND_{OUTER_MODE} (SUBREG_{INNER_MODE} (REG + INNER_STEP))
  
!    If the operation cannot be described in this shape, return false.
!    LAST_DEF is the definition of REG that dominates loop latch.  */
  
  static bool
! get_biv_step (struct ref *last_def, rtx reg, rtx *inner_step,
! 	      enum machine_mode *inner_mode, enum rtx_code *extend,
! 	      enum machine_mode *outer_mode, rtx *outer_step)
  {
    *outer_mode = GET_MODE (reg);
  
!   if (!get_biv_step_1 (last_def, reg,
  		       inner_step, inner_mode, extend, *outer_mode,
  		       outer_step))
      return false;
*************** get_biv_step (rtx reg, rtx *inner_step, 
*** 833,848 ****
    return true;
  }
  
  /* Determines whether DEF is a biv and if so, stores its description
     to *IV.  */
  
  static bool
  iv_analyze_biv (rtx def, struct rtx_iv *iv)
  {
-   unsigned regno;
    rtx inner_step, outer_step;
    enum machine_mode inner_mode, outer_mode;
    enum rtx_code extend;
  
    if (dump_file)
      {
--- 782,835 ----
    return true;
  }
  
+ /* Records information that DEF is induction variable IV.  */
+ 
+ static void
+ record_iv (struct ref *def, struct rtx_iv *iv)
+ {
+   struct rtx_iv *recorded_iv = xmalloc (sizeof (struct rtx_iv));
+ 
+   *recorded_iv = *iv;
+   DF_REF_IV_SET (def, recorded_iv);
+ }
+ 
+ /* If DEF was already analyzed for bivness, store the description of the biv to
+    IV and return true.  Otherwise return false.  */
+ 
+ static bool
+ analyzed_for_bivness_p (rtx def, struct rtx_iv *iv)
+ {
+   struct biv_entry *biv = htab_find_with_hash (bivs, def, REGNO (def));
+ 
+   if (!biv)
+     return false;
+ 
+   *iv = biv->iv;
+   return true;
+ }
+ 
+ static void
+ record_biv (rtx def, struct rtx_iv *iv)
+ {
+   struct biv_entry *biv = xmalloc (sizeof (struct biv_entry));
+   void **slot = htab_find_slot_with_hash (bivs, def, REGNO (def), INSERT);
+ 
+   biv->regno = REGNO (def);
+   biv->iv = *iv;
+   gcc_assert (!*slot);
+   *slot = biv;
+ }
+ 
  /* Determines whether DEF is a biv and if so, stores its description
     to *IV.  */
  
  static bool
  iv_analyze_biv (rtx def, struct rtx_iv *iv)
  {
    rtx inner_step, outer_step;
    enum machine_mode inner_mode, outer_mode;
    enum rtx_code extend;
+   struct ref *last_def;
  
    if (dump_file)
      {
*************** iv_analyze_biv (rtx def, struct rtx_iv *
*** 859,889 ****
        return iv_constant (iv, def, VOIDmode);
      }
  
!   regno = REGNO (def);
!   if (last_def[regno] == const0_rtx)
      {
        if (dump_file)
  	fprintf (dump_file, "  not simple.\n");
        return false;
      }
  
!   if (last_def[regno] && bivs[regno].analysed)
      {
        if (dump_file)
  	fprintf (dump_file, "  already analysed.\n");
- 
-       *iv = bivs[regno];
        return iv->base != NULL_RTX;
      }
  
!   if (!last_def[regno])
!     {
!       iv_constant (iv, def, VOIDmode);
!       goto end;
!     }
! 
!   iv->analysed = true;
!   if (!get_biv_step (def, &inner_step, &inner_mode, &extend,
  		     &outer_mode, &outer_step))
      {
        iv->base = NULL_RTX;
--- 846,869 ----
        return iv_constant (iv, def, VOIDmode);
      }
  
!   if (!latch_dominating_def (def, &last_def))
      {
        if (dump_file)
  	fprintf (dump_file, "  not simple.\n");
        return false;
      }
  
!   if (!last_def)
!     return iv_constant (iv, def, VOIDmode);
! 
!   if (analyzed_for_bivness_p (def, iv))
      {
        if (dump_file)
  	fprintf (dump_file, "  already analysed.\n");
        return iv->base != NULL_RTX;
      }
  
!   if (!get_biv_step (last_def, def, &inner_step, &inner_mode, &extend,
  		     &outer_mode, &outer_step))
      {
        iv->base = NULL_RTX;
*************** iv_analyze_biv (rtx def, struct rtx_iv *
*** 913,1031 ****
        fprintf (dump_file, "\n");
      }
  
!   bivs[regno] = *iv;
! 
    return iv->base != NULL_RTX;
  }
  
! /* Analyzes operand OP of INSN and stores the result to *IV.  */
  
! static bool
! iv_analyze_op (rtx insn, rtx op, struct rtx_iv *iv)
  {
!   rtx def_insn;
!   unsigned regno;
!   bool inv = CONSTANT_P (op);
! 
!   if (dump_file)
!     {
!       fprintf (dump_file, "Analyzing operand ");
!       print_rtl (dump_file, op);
!       fprintf (dump_file, " of insn ");
!       print_rtl_single (dump_file, insn);
!     }
! 
!   if (GET_CODE (op) == SUBREG)
!     {
!       if (!subreg_lowpart_p (op))
! 	return false;
  
!       if (!iv_analyze_op (insn, SUBREG_REG (op), iv))
! 	return false;
  
!       return iv_subreg (iv, GET_MODE (op));
!     }
  
!   if (!inv)
      {
!       regno = REGNO (op);
!       if (!last_def[regno])
! 	inv = true;
!       else if (last_def[regno] == const0_rtx)
  	{
! 	  if (dump_file)
! 	    fprintf (dump_file, "  not simple.\n");
! 	  return false;
  	}
      }
  
!   if (inv)
      {
!       iv_constant (iv, op, VOIDmode);
  
!       if (dump_file)
  	{
! 	  fprintf (dump_file, "  ");
! 	  dump_iv_info (dump_file, iv);
! 	  fprintf (dump_file, "\n");
  	}
!       return true;
!     }
  
!   def_insn = iv_get_reaching_def (insn, op);
!   if (def_insn == const0_rtx)
!     {
!       if (dump_file)
! 	fprintf (dump_file, "  not simple.\n");
        return false;
      }
  
!   return iv_analyze (def_insn, op, iv);
! }
! 
! /* Analyzes iv DEF defined in INSN and stores the result to *IV.  */
! 
! bool
! iv_analyze (rtx insn, rtx def, struct rtx_iv *iv)
! {
!   unsigned uid;
!   rtx set, rhs, mby = NULL_RTX, tmp;
!   rtx op0 = NULL_RTX, op1 = NULL_RTX;
!   struct rtx_iv iv0, iv1;
!   enum machine_mode amode;
!   enum rtx_code code;
  
!   if (insn == const0_rtx)
      return false;
  
!   if (GET_CODE (def) == SUBREG)
      {
!       if (!subreg_lowpart_p (def))
  	return false;
  
!       if (!iv_analyze (insn, SUBREG_REG (def), iv))
  	return false;
  
!       return iv_subreg (iv, GET_MODE (def));
      }
  
!   if (!insn)
!     return iv_analyze_biv (def, iv);
  
    if (dump_file)
      {
!       fprintf (dump_file, "Analyzing def of ");
!       print_rtl (dump_file, def);
        fprintf (dump_file, " in insn ");
        print_rtl_single (dump_file, insn);
      }
  
!   uid = INSN_UID (insn);
!   if (insn_info[uid].iv.analysed)
      {
        if (dump_file)
  	fprintf (dump_file, "  already analysed.\n");
!       *iv = insn_info[uid].iv;
        return iv->base != NULL_RTX;
      }
  
--- 893,1046 ----
        fprintf (dump_file, "\n");
      }
  
!   record_biv (def, iv);
    return iv->base != NULL_RTX;
  }
  
! /* Analyzes expression RHS used at INSN and stores the result to *IV. 
!    The mode of the induction variable is MODE.  */
  
! bool
! iv_analyze_expr (rtx insn, rtx rhs, enum machine_mode mode, struct rtx_iv *iv)
  {
!   rtx mby = NULL_RTX, tmp;
!   rtx op0 = NULL_RTX, op1 = NULL_RTX;
!   struct rtx_iv iv0, iv1;
!   enum rtx_code code = GET_CODE (rhs);
!   enum machine_mode omode = mode;
  
!   iv->mode = VOIDmode;
!   iv->base = NULL_RTX;
!   iv->step = NULL_RTX;
  
!   gcc_assert (GET_MODE (rhs) == mode || GET_MODE (rhs) == VOIDmode);
  
!   if (CONSTANT_P (rhs)
!       || REG_P (rhs)
!       || code == SUBREG)
      {
!       if (!iv_analyze_op (insn, rhs, iv))
! 	return false;
! 	
!       if (iv->mode == VOIDmode)
  	{
! 	  iv->mode = mode;
! 	  iv->extend_mode = mode;
  	}
+ 
+       return true;
      }
  
!   switch (code)
      {
!     case REG:
!       op0 = rhs;
!       break;
  
!     case SIGN_EXTEND:
!     case ZERO_EXTEND:
!     case NEG:
!       op0 = XEXP (rhs, 0);
!       omode = GET_MODE (op0);
!       break;
! 
!     case PLUS:
!     case MINUS:
!       op0 = XEXP (rhs, 0);
!       op1 = XEXP (rhs, 1);
!       break;
! 
!     case MULT:
!       op0 = XEXP (rhs, 0);
!       mby = XEXP (rhs, 1);
!       if (!CONSTANT_P (mby))
  	{
! 	  tmp = op0;
! 	  op0 = mby;
! 	  mby = tmp;
  	}
!       if (!CONSTANT_P (mby))
! 	return false;
!       break;
  
!     case ASHIFT:
!       op0 = XEXP (rhs, 0);
!       mby = XEXP (rhs, 1);
!       if (!CONSTANT_P (mby))
! 	return false;
!       break;
! 
!     default:
        return false;
      }
  
!   if (op0
!       && !iv_analyze_expr (insn, op0, omode, &iv0))
!     return false;
  
!   if (op1
!       && !iv_analyze_expr (insn, op1, omode, &iv1))
      return false;
  
!   switch (code)
      {
!     case SIGN_EXTEND:
!     case ZERO_EXTEND:
!       if (!iv_extend (&iv0, code, mode))
! 	return false;
!       break;
! 
!     case NEG:
!       if (!iv_neg (&iv0))
  	return false;
+       break;
  
!     case PLUS:
!     case MINUS:
!       if (!iv_add (&iv0, &iv1, code))
  	return false;
+       break;
  
!     case MULT:
!       if (!iv_mult (&iv0, mby))
! 	return false;
!       break;
! 
!     case ASHIFT:
!       if (!iv_shift (&iv0, mby))
! 	return false;
!       break;
! 
!     default:
!       break;
      }
  
!   *iv = iv0;
!   return iv->base != NULL_RTX;
! }
! 
! /* Analyzes iv DEF and stores the result to *IV.  */
! 
! static bool
! iv_analyze_def (struct ref *def, struct rtx_iv *iv)
! {
!   rtx insn = DF_REF_INSN (def);
!   rtx reg = DF_REF_REG (def);
!   rtx set, rhs;
  
    if (dump_file)
      {
!       fprintf (dump_file, "Analysing def of ");
!       print_rtl (dump_file, reg);
        fprintf (dump_file, " in insn ");
        print_rtl_single (dump_file, insn);
      }
  
!   if (DF_REF_IV (def))
      {
        if (dump_file)
  	fprintf (dump_file, "  already analysed.\n");
!       *iv = *DF_REF_IV (def);
        return iv->base != NULL_RTX;
      }
  
*************** iv_analyze (rtx insn, rtx def, struct rt
*** 1034,1179 ****
    iv->step = NULL_RTX;
  
    set = single_set (insn);
    rhs = find_reg_equal_equiv_note (insn);
    if (rhs)
      rhs = XEXP (rhs, 0);
    else
      rhs = SET_SRC (set);
-   code = GET_CODE (rhs);
  
!   if (CONSTANT_P (rhs))
      {
!       op0 = rhs;
!       amode = GET_MODE (def);
      }
-   else
-     {
-       switch (code)
- 	{
- 	case SUBREG:
- 	  if (!subreg_lowpart_p (rhs))
- 	    goto end;
- 	  op0 = rhs;
- 	  break;
- 	  
- 	case REG:
- 	  op0 = rhs;
- 	  break;
  
! 	case SIGN_EXTEND:
! 	case ZERO_EXTEND:
! 	case NEG:
! 	  op0 = XEXP (rhs, 0);
! 	  break;
  
! 	case PLUS:
! 	case MINUS:
! 	  op0 = XEXP (rhs, 0);
! 	  op1 = XEXP (rhs, 1);
! 	  break;
  
! 	case MULT:
! 	  op0 = XEXP (rhs, 0);
! 	  mby = XEXP (rhs, 1);
! 	  if (!CONSTANT_P (mby))
! 	    {
! 	      gcc_assert (CONSTANT_P (op0));
! 	      tmp = op0;
! 	      op0 = mby;
! 	      mby = tmp;
! 	    }
! 	  break;
  
! 	case ASHIFT:
! 	  gcc_assert (!CONSTANT_P (XEXP (rhs, 0)));
! 	  op0 = XEXP (rhs, 0);
! 	  mby = XEXP (rhs, 1);
! 	  break;
  
! 	default:
! 	  gcc_unreachable ();
! 	}
  
!       amode = GET_MODE (rhs);
!     }
  
!   if (op0)
      {
!       if (!iv_analyze_op (insn, op0, &iv0))
! 	goto end;
! 	
!       if (iv0.mode == VOIDmode)
  	{
! 	  iv0.mode = amode;
! 	  iv0.extend_mode = amode;
  	}
      }
  
!   if (op1)
      {
!       if (!iv_analyze_op (insn, op1, &iv1))
! 	goto end;
  
!       if (iv1.mode == VOIDmode)
  	{
! 	  iv1.mode = amode;
! 	  iv1.extend_mode = amode;
  	}
      }
  
!   switch (code)
!     {
!     case SIGN_EXTEND:
!     case ZERO_EXTEND:
!       if (!iv_extend (&iv0, code, amode))
! 	goto end;
!       break;
  
!     case NEG:
!       if (!iv_neg (&iv0))
! 	goto end;
!       break;
  
!     case PLUS:
!     case MINUS:
!       if (!iv_add (&iv0, &iv1, code))
! 	goto end;
!       break;
  
!     case MULT:
!       if (!iv_mult (&iv0, mby))
! 	goto end;
!       break;
  
!     case ASHIFT:
!       if (!iv_shift (&iv0, mby))
! 	goto end;
!       break;
  
!     default:
!       break;
      }
  
!   *iv = iv0;
  
!  end:
!   iv->analysed = true;
!   insn_info[uid].iv = *iv;
  
!   if (dump_file)
!     {
!       print_rtl (dump_file, def);
!       fprintf (dump_file, " in insn ");
!       print_rtl_single (dump_file, insn);
!       fprintf (dump_file, "  is ");
!       dump_iv_info (dump_file, iv);
!       fprintf (dump_file, "\n");
!     }
  
!   return iv->base != NULL_RTX;
  }
  
! /* Checks whether definition of register REG in INSN a basic induction
     variable.  IV analysis must have been initialized (via a call to
     iv_analysis_loop_init) for this function to produce a result.  */
  
--- 1049,1177 ----
    iv->step = NULL_RTX;
  
    set = single_set (insn);
+   if (!set || SET_DEST (set) != reg)
+     return false;
+ 
    rhs = find_reg_equal_equiv_note (insn);
    if (rhs)
      rhs = XEXP (rhs, 0);
    else
      rhs = SET_SRC (set);
  
!   iv_analyze_expr (insn, rhs, GET_MODE (reg), iv);
!   record_iv (def, iv);
! 
!   if (dump_file)
      {
!       print_rtl (dump_file, reg);
!       fprintf (dump_file, " in insn ");
!       print_rtl_single (dump_file, insn);
!       fprintf (dump_file, "  is ");
!       dump_iv_info (dump_file, iv);
!       fprintf (dump_file, "\n");
      }
  
!   return iv->base != NULL_RTX;
! }
  
! /* Analyzes operand OP of INSN and stores the result to *IV.  */
  
! static bool
! iv_analyze_op (rtx insn, rtx op, struct rtx_iv *iv)
! {
!   struct ref *def = NULL;
!   enum iv_grd_result res;
  
!   if (dump_file)
!     {
!       fprintf (dump_file, "Analysing operand ");
!       print_rtl (dump_file, op);
!       fprintf (dump_file, " of insn ");
!       print_rtl_single (dump_file, insn);
!     }
  
!   if (CONSTANT_P (op))
!     res = GRD_INVARIANT;
!   else if (GET_CODE (op) == SUBREG)
!     {
!       if (!subreg_lowpart_p (op))
! 	return false;
  
!       if (!iv_analyze_op (insn, SUBREG_REG (op), iv))
! 	return false;
  
!       return iv_subreg (iv, GET_MODE (op));
!     }
!   else
      {
!       res = iv_get_reaching_def (insn, op, &def);
!       if (res == GRD_INVALID)
  	{
! 	  if (dump_file)
! 	    fprintf (dump_file, "  not simple.\n");
! 	  return false;
  	}
      }
  
!   if (res == GRD_INVARIANT)
      {
!       iv_constant (iv, op, VOIDmode);
  
!       if (dump_file)
  	{
! 	  fprintf (dump_file, "  ");
! 	  dump_iv_info (dump_file, iv);
! 	  fprintf (dump_file, "\n");
  	}
+       return true;
      }
  
!   if (res == GRD_MAYBE_BIV)
!     return iv_analyze_biv (op, iv);
  
!   return iv_analyze_def (def, iv);
! }
  
! /* Analyzes value VAL at INSN and stores the result to *IV.  */
  
! bool
! iv_analyze (rtx insn, rtx val, struct rtx_iv *iv)
! {
!   rtx reg;
  
!   /* We must find the insn in that val is used, so that we get to UD chains.
!      Since the function is sometimes called on result of get_condition,
!      this does not necessarily have to be directly INSN; scan also the
!      following insns.  */
!   if (simple_reg_p (val))
!     {
!       if (GET_CODE (val) == SUBREG)
! 	reg = SUBREG_REG (val);
!       else
! 	reg = val;
  
!       while (!df_find_use (df, insn, reg))
! 	insn = NEXT_INSN (insn);
      }
  
!   return iv_analyze_op (insn, val, iv);
! }
  
! /* Analyzes definition of DEF in INSN and stores the result to IV.  */
  
! bool
! iv_analyze_result (rtx insn, rtx def, struct rtx_iv *iv)
! {
!   struct ref *adef;
  
!   adef = df_find_def (df, insn, def);
!   if (!adef)
!     return false;
! 
!   return iv_analyze_def (adef, iv);
  }
  
! /* Checks whether definition of register REG in INSN is a basic induction
     variable.  IV analysis must have been initialized (via a call to
     iv_analysis_loop_init) for this function to produce a result.  */
  
*************** bool
*** 1181,1194 ****
  biv_p (rtx insn, rtx reg)
  {
    struct rtx_iv iv;
  
!   if (!REG_P (reg))
      return false;
  
!   if (last_def[REGNO (reg)] != insn)
      return false;
  
!   return iv_analyze_biv (reg, &iv);
  }
  
  /* Calculates value of IV at ITERATION-th iteration.  */
--- 1179,1200 ----
  biv_p (rtx insn, rtx reg)
  {
    struct rtx_iv iv;
+   struct ref *def, *last_def;
  
!   if (!simple_reg_p (reg))
      return false;
  
!   def = df_find_def (df, insn, reg);
!   gcc_assert (def != NULL);
!   if (!latch_dominating_def (reg, &last_def))
!     return false;
!   if (last_def != def)
      return false;
  
!   if (!iv_analyze_biv (reg, &iv))
!     return false;
! 
!   return iv.step != const0_rtx;
  }
  
  /* Calculates value of IV at ITERATION-th iteration.  */
*************** get_iv_value (struct rtx_iv *iv, rtx ite
*** 1230,1250 ****
  void
  iv_analysis_done (void)
  {
!   max_insn_no = 0;
!   max_reg_no = 0;
!   if (insn_info)
!     {
!       free (insn_info);
!       insn_info = NULL;
!     }
!   if (last_def)
!     {
!       free (last_def);
!       last_def = NULL;
!     }
!   if (bivs)
      {
!       free (bivs);
        bivs = NULL;
      }
  }
--- 1236,1247 ----
  void
  iv_analysis_done (void)
  {
!   if (df)
      {
!       clear_iv_info ();
!       df_finish (df);
!       df = NULL;
!       htab_delete (bivs);
        bivs = NULL;
      }
  }
*************** static void
*** 1996,2002 ****
  iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition,
  			 struct niter_desc *desc)
  {
!   rtx op0, op1, delta, step, bound, may_xform, def_insn, tmp, tmp0, tmp1;
    struct rtx_iv iv0, iv1, tmp_iv;
    rtx assumption, may_not_xform;
    enum rtx_code cond;
--- 1993,1999 ----
  iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition,
  			 struct niter_desc *desc)
  {
!   rtx op0, op1, delta, step, bound, may_xform, tmp, tmp0, tmp1;
    struct rtx_iv iv0, iv1, tmp_iv;
    rtx assumption, may_not_xform;
    enum rtx_code cond;
*************** iv_number_of_iterations (struct loop *lo
*** 2038,2052 ****
      goto fail;
  
    op0 = XEXP (condition, 0);
!   def_insn = iv_get_reaching_def (insn, op0);
!   if (!iv_analyze (def_insn, op0, &iv0))
      goto fail;
    if (iv0.extend_mode == VOIDmode)
      iv0.mode = iv0.extend_mode = mode;
    
    op1 = XEXP (condition, 1);
!   def_insn = iv_get_reaching_def (insn, op1);
!   if (!iv_analyze (def_insn, op1, &iv1))
      goto fail;
    if (iv1.extend_mode == VOIDmode)
      iv1.mode = iv1.extend_mode = mode;
--- 2035,2047 ----
      goto fail;
  
    op0 = XEXP (condition, 0);
!   if (!iv_analyze (insn, op0, &iv0))
      goto fail;
    if (iv0.extend_mode == VOIDmode)
      iv0.mode = iv0.extend_mode = mode;
    
    op1 = XEXP (condition, 1);
!   if (!iv_analyze (insn, op1, &iv1))
      goto fail;
    if (iv1.extend_mode == VOIDmode)
      iv1.mode = iv1.extend_mode = mode;
Index: cfgloop.h
===================================================================
*** cfgloop.h	(revision 107537)
--- cfgloop.h	(working copy)
*************** struct rtx_iv
*** 352,360 ****
    /* The mode the variable iterates in.  */
    enum machine_mode mode;
  
-   /* Whether we have already filled the remaining fields.  */
-   unsigned analysed : 1;
- 
    /* Whether the first iteration needs to be handled specially.  */
    unsigned first_special : 1;
  };
--- 352,357 ----
*************** struct niter_desc
*** 404,415 ****
  };
  
  extern void iv_analysis_loop_init (struct loop *);
- extern rtx iv_get_reaching_def (rtx, rtx);
  extern bool iv_analyze (rtx, rtx, struct rtx_iv *);
  extern rtx get_iv_value (struct rtx_iv *, rtx);
  extern bool biv_p (rtx, rtx);
  extern void find_simple_exit (struct loop *, struct niter_desc *);
  extern void iv_analysis_done (void);
  
  extern struct niter_desc *get_simple_loop_desc (struct loop *loop);
  extern void free_simple_loop_desc (struct loop *loop);
--- 401,414 ----
  };
  
  extern void iv_analysis_loop_init (struct loop *);
  extern bool iv_analyze (rtx, rtx, struct rtx_iv *);
+ extern bool iv_analyze_result (rtx, rtx, struct rtx_iv *);
+ extern bool iv_analyze_expr (rtx, rtx, enum machine_mode, struct rtx_iv *);
  extern rtx get_iv_value (struct rtx_iv *, rtx);
  extern bool biv_p (rtx, rtx);
  extern void find_simple_exit (struct loop *, struct niter_desc *);
  extern void iv_analysis_done (void);
+ extern struct df *iv_current_loop_df (void);
  
  extern struct niter_desc *get_simple_loop_desc (struct loop *loop);
  extern void free_simple_loop_desc (struct loop *loop);
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 107537)
--- Makefile.in	(working copy)
*************** cfgloopanal.o : cfgloopanal.c $(CONFIG_H
*** 2318,2324 ****
     $(OBSTACK_H) output.h
  loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
     hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
!    output.h intl.h
  loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
     $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h \
     $(TM_H) $(TM_P_H) function.h $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h
--- 2318,2324 ----
     $(OBSTACK_H) output.h
  loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
     hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
!    output.h intl.h $(DF_H) $(HASHTAB_H)
  loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
     $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h \
     $(TM_H) $(TM_P_H) function.h $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h
*************** loop-unswitch.o : loop-unswitch.c $(CONF
*** 2333,2339 ****
     output.h $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H)
  loop-unroll.o: loop-unroll.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \
     $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) $(PARAMS_H) \
!    output.h $(EXPR_H) coretypes.h $(TM_H) $(HASHTAB_H) $(RECOG_H) $(VARRAY_H) \
     $(OBSTACK_H)
  dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h $(OBSTACK_H) toplev.h
--- 2333,2339 ----
     output.h $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H)
  loop-unroll.o: loop-unroll.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \
     $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) $(PARAMS_H) \
!    output.h $(EXPR_H) coretypes.h $(TM_H) $(HASHTAB_H) $(RECOG_H) \
     $(OBSTACK_H)
  dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h $(OBSTACK_H) toplev.h


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]