OSDN Git Service

2006-02-02 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-loop-ivopts.c
index c5b6e40..4925d45 100644 (file)
@@ -1,5 +1,5 @@
 /* Induction variable optimizations.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
    
 This file is part of GCC.
    
@@ -15,8 +15,8 @@ for more details.
    
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This pass tries to find the optimal set of induction variables for the loop.
    It optimizes just the basic linear induction variables (although adding
@@ -88,6 +88,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree-scalar-evolution.h"
 #include "cfgloop.h"
 #include "params.h"
+#include "langhooks.h"
 
 /* The infinite cost.  */
 #define INFTY 10000000
@@ -96,14 +97,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    this.  */
 #define AVG_LOOP_NITER(LOOP) 5
 
-/* Just to shorten the ugly names.  */
-#define EXEC_BINARY nondestructive_fold_binary_to_constant
-#define EXEC_UNARY nondestructive_fold_unary_to_constant
 
 /* Representation of the induction variable.  */
 struct iv
 {
   tree base;           /* Initial value of the iv.  */
+  tree base_object;    /* A memory object to that the induction variable points.  */
   tree step;           /* Step of the iv (constant only).  */
   tree ssa_name;       /* The ssa name with the value.  */
   bool biv_p;          /* Is it a biv?  */
@@ -125,9 +124,6 @@ struct version_info
 /* Information attached to loop.  */
 struct loop_data
 {
-  struct tree_niter_desc niter;
-                       /* Number of iterations.  */
-
   unsigned regs_used;  /* Number of registers used.  */
 };
 
@@ -147,6 +143,9 @@ struct cost_pair
   unsigned cost;       /* The cost.  */
   bitmap depends_on;   /* The list of invariants that have to be
                           preserved.  */
+  tree value;          /* For final value elimination, the expression for
+                          the final value of the iv.  For iv elimination,
+                          the new bound to compare with.  */
 };
 
 /* Use.  */
@@ -157,7 +156,8 @@ struct iv_use
   struct iv *iv;       /* The induction variable it is based on.  */
   tree stmt;           /* Statement in that it occurs.  */
   tree *op_p;          /* The place where it occurs.  */
-  bitmap related_cands;        /* The set of "related" iv candidates.  */
+  bitmap related_cands;        /* The set of "related" iv candidates, plus the common
+                          important ones.  */
 
   unsigned n_map_members; /* Number of candidates in the cost_map list.  */
   struct cost_pair *cost_map;
@@ -191,15 +191,28 @@ struct iv_cand
                           to replace the final value of an iv by direct
                           computation of the value.  */
   unsigned cost;       /* Cost of the candidate.  */
+  bitmap depends_on;   /* The list of invariants that are used in step of the
+                          biv.  */
 };
 
 /* The data used by the induction variable optimizations.  */
 
+typedef struct iv_use *iv_use_p;
+DEF_VEC_P(iv_use_p);
+DEF_VEC_ALLOC_P(iv_use_p,heap);
+
+typedef struct iv_cand *iv_cand_p;
+DEF_VEC_P(iv_cand_p);
+DEF_VEC_ALLOC_P(iv_cand_p,heap);
+
 struct ivopts_data
 {
   /* The currently optimized loop.  */
   struct loop *current_loop;
 
+  /* Numbers of iterations for all exits of the current loop.  */
+  htab_t niters;
+
   /* The size of version_info array allocated.  */
   unsigned version_info_size;
 
@@ -213,16 +226,74 @@ struct ivopts_data
   unsigned max_inv_id;
 
   /* The uses of induction variables.  */
-  varray_type iv_uses;
+  VEC(iv_use_p,heap) *iv_uses;
 
   /* The candidates.  */
-  varray_type iv_candidates;
+  VEC(iv_cand_p,heap) *iv_candidates;
+
+  /* A bitmap of important candidates.  */
+  bitmap important_candidates;
 
   /* Whether to consider just related and important candidates when replacing a
      use.  */
   bool consider_all_candidates;
 };
 
+/* An assignment of iv candidates to uses.  */
+
+struct iv_ca
+{
+  /* The number of uses covered by the assignment.  */
+  unsigned upto;
+
+  /* Number of uses that cannot be expressed by the candidates in the set.  */
+  unsigned bad_uses;
+
+  /* Candidate assigned to a use, together with the related costs.  */
+  struct cost_pair **cand_for_use;
+
+  /* Number of times each candidate is used.  */
+  unsigned *n_cand_uses;
+
+  /* The candidates used.  */
+  bitmap cands;
+
+  /* The number of candidates in the set.  */
+  unsigned n_cands;
+
+  /* Total number of registers needed.  */
+  unsigned n_regs;
+
+  /* Total cost of expressing uses.  */
+  unsigned cand_use_cost;
+
+  /* Total cost of candidates.  */
+  unsigned cand_cost;
+
+  /* Number of times each invariant is used.  */
+  unsigned *n_invariant_uses;
+
+  /* Total cost of the assignment.  */
+  unsigned cost;
+};
+
+/* Difference of two iv candidate assignments.  */
+
+struct iv_ca_delta
+{
+  /* Changed use.  */
+  struct iv_use *use;
+
+  /* An old assignment (for rollback purposes).  */
+  struct cost_pair *old_cp;
+
+  /* A new assignment.  */
+  struct cost_pair *new_cp;
+
+  /* Next change in the list.  */
+  struct iv_ca_delta *next_change;
+};
+
 /* Bound on number of candidates below that all candidates are considered.  */
 
 #define CONSIDER_ALL_CANDIDATES_BOUND \
@@ -234,17 +305,23 @@ struct ivopts_data
 #define MAX_CONSIDERED_USES \
   ((unsigned) PARAM_VALUE (PARAM_IV_MAX_CONSIDERED_USES))
 
+/* If there are at most this number of ivs in the set, try removing unnecessary
+   ivs from the set always.  */
+
+#define ALWAYS_PRUNE_CAND_SET_BOUND \
+  ((unsigned) PARAM_VALUE (PARAM_IV_ALWAYS_PRUNE_CAND_SET_BOUND))
+
 /* The list of trees for that the decl_rtl field must be reset is stored
    here.  */
 
-static varray_type decl_rtl_to_reset;
+static VEC(tree,heap) *decl_rtl_to_reset;
 
 /* Number of uses recorded in DATA.  */
 
 static inline unsigned
 n_iv_uses (struct ivopts_data *data)
 {
-  return VARRAY_ACTIVE_SIZE (data->iv_uses);
+  return VEC_length (iv_use_p, data->iv_uses);
 }
 
 /* Ith use recorded in DATA.  */
@@ -252,7 +329,7 @@ n_iv_uses (struct ivopts_data *data)
 static inline struct iv_use *
 iv_use (struct ivopts_data *data, unsigned i)
 {
-  return VARRAY_GENERIC_PTR_NOGC (data->iv_uses, i);
+  return VEC_index (iv_use_p, data->iv_uses, i);
 }
 
 /* Number of candidates recorded in DATA.  */
@@ -260,7 +337,7 @@ iv_use (struct ivopts_data *data, unsigned i)
 static inline unsigned
 n_iv_cands (struct ivopts_data *data)
 {
-  return VARRAY_ACTIVE_SIZE (data->iv_candidates);
+  return VEC_length (iv_cand_p, data->iv_candidates);
 }
 
 /* Ith candidate recorded in DATA.  */
@@ -268,7 +345,7 @@ n_iv_cands (struct ivopts_data *data)
 static inline struct iv_cand *
 iv_cand (struct ivopts_data *data, unsigned i)
 {
-  return VARRAY_GENERIC_PTR_NOGC (data->iv_candidates, i);
+  return VEC_index (iv_cand_p, data->iv_candidates, i);
 }
 
 /* The data for LOOP.  */
@@ -281,7 +358,7 @@ loop_data (struct loop *loop)
 
 /* The single loop exit if it dominates the latch, NULL otherwise.  */
 
-static edge
+edge
 single_dom_exit (struct loop *loop)
 {
   edge exit = loop->single_exit;
@@ -301,8 +378,15 @@ extern void dump_iv (FILE *, struct iv *);
 void
 dump_iv (FILE *file, struct iv *iv)
 {
-  fprintf (file, "ssa name ");
-  print_generic_expr (file, iv->ssa_name, TDF_SLIM);
+  if (iv->ssa_name)
+    {
+      fprintf (file, "ssa name ");
+      print_generic_expr (file, iv->ssa_name, TDF_SLIM);
+      fprintf (file, "\n");
+    }
+
+  fprintf (file, "  type ");
+  print_generic_expr (file, TREE_TYPE (iv->base), TDF_SLIM);
   fprintf (file, "\n");
 
   if (iv->step)
@@ -322,6 +406,13 @@ dump_iv (FILE *file, struct iv *iv)
       fprintf (file, "\n");
     }
 
+  if (iv->base_object)
+    {
+      fprintf (file, "  base object ");
+      print_generic_expr (file, iv->base_object, TDF_SLIM);
+      fprintf (file, "\n");
+    }
+
   if (iv->biv_p)
     fprintf (file, "  is a biv\n");
 }
@@ -332,8 +423,6 @@ extern void dump_use (FILE *, struct iv_use *);
 void
 dump_use (FILE *file, struct iv_use *use)
 {
-  struct iv *iv = use->iv;
-
   fprintf (file, "use %d\n", use->id);
 
   switch (use->type)
@@ -355,37 +444,25 @@ dump_use (FILE *file, struct iv_use *use)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
-   fprintf (file, "  in statement ");
-   print_generic_expr (file, use->stmt, TDF_SLIM);
-   fprintf (file, "\n");
-
-   fprintf (file, "  at position ");
-   if (use->op_p)
-     print_generic_expr (file, *use->op_p, TDF_SLIM);
-   fprintf (file, "\n");
+  fprintf (file, "  in statement ");
+  print_generic_expr (file, use->stmt, TDF_SLIM);
+  fprintf (file, "\n");
 
-   if (iv->step)
-     {
-       fprintf (file, "  base ");
-       print_generic_expr (file, iv->base, TDF_SLIM);
-       fprintf (file, "\n");
+  fprintf (file, "  at position ");
+  if (use->op_p)
+    print_generic_expr (file, *use->op_p, TDF_SLIM);
+  fprintf (file, "\n");
 
-       fprintf (file, "  step ");
-       print_generic_expr (file, iv->step, TDF_SLIM);
-       fprintf (file, "\n");
-     }
-   else
-     {
-       fprintf (file, "  invariant ");
-       print_generic_expr (file, iv->base, TDF_SLIM);
-       fprintf (file, "\n");
-     }
+  dump_iv (file, use->iv);
 
-   fprintf (file, "  related candidates ");
-   dump_bitmap (file, use->related_cands);
+  if (use->related_cands)
+    {
+      fprintf (file, "  related candidates ");
+      dump_bitmap (file, use->related_cands);
+    }
 }
 
 /* Dumps information about the uses to FILE.  */
@@ -417,6 +494,12 @@ dump_cand (FILE *file, struct iv_cand *cand)
   fprintf (file, "candidate %d%s\n",
           cand->id, cand->important ? " (important)" : "");
 
+  if (cand->depends_on)
+    {
+      fprintf (file, "  depends on ");
+      dump_bitmap (file, cand->depends_on);
+    }
+
   if (!iv)
     {
       fprintf (file, "  final value replacement\n");
@@ -438,22 +521,7 @@ dump_cand (FILE *file, struct iv_cand *cand)
       break;
     }
 
-   if (iv->step)
-     {
-       fprintf (file, "  base ");
-       print_generic_expr (file, iv->base, TDF_SLIM);
-       fprintf (file, "\n");
-
-       fprintf (file, "  step ");
-       print_generic_expr (file, iv->step, TDF_SLIM);
-       fprintf (file, "\n");
-     }
-   else
-     {
-       fprintf (file, "  invariant ");
-       print_generic_expr (file, iv->base, TDF_SLIM);
-       fprintf (file, "\n");
-     }
+  dump_iv (file, iv);
 }
 
 /* Returns the info for ssa version VER.  */
@@ -513,8 +581,7 @@ divide (unsigned bits, unsigned HOST_WIDE_INT a, unsigned HOST_WIDE_INT b,
 
   val = (a * inv) & mask;
 
-  if (((val * b) & mask) != a)
-    abort ();
+  gcc_assert (((val * b) & mask) == a);
 
   if ((val >> (bits - 1)) & 1)
     val |= ~mask;
@@ -532,8 +599,7 @@ stmt_after_ip_normal_pos (struct loop *loop, tree stmt)
 {
   basic_block bb = ip_normal_pos (loop), sbb = bb_for_stmt (stmt);
 
-  if (!bb)
-    abort ();
+  gcc_assert (bb);
 
   if (sbb == loop->latch)
     return true;
@@ -589,8 +655,89 @@ stmt_after_increment (struct loop *loop, struct iv_cand *cand, tree stmt)
       return stmt_after_ip_original_pos (cand, stmt);
 
     default:
-      abort ();
+      gcc_unreachable ();
+    }
+}
+
+/* Element of the table in that we cache the numbers of iterations obtained
+   from exits of the loop.  */
+
+struct nfe_cache_elt
+{
+  /* The edge for that the number of iterations is cached.  */
+  edge exit;
+
+  /* True if the # of iterations was successfully determined.  */
+  bool valid_p;
+
+  /* Description of # of iterations.  */
+  struct tree_niter_desc niter;
+};
+
+/* Hash function for nfe_cache_elt E.  */
+
+static hashval_t
+nfe_hash (const void *e)
+{
+  const struct nfe_cache_elt *elt = e;
+
+  return htab_hash_pointer (elt->exit);
+}
+
+/* Equality function for nfe_cache_elt E1 and edge E2.  */
+
+static int
+nfe_eq (const void *e1, const void *e2)
+{
+  const struct nfe_cache_elt *elt1 = e1;
+
+  return elt1->exit == e2;
+}
+
+/*  Returns structure describing number of iterations determined from
+    EXIT of DATA->current_loop, or NULL if something goes wrong.  */
+
+static struct tree_niter_desc *
+niter_for_exit (struct ivopts_data *data, edge exit)
+{
+  struct nfe_cache_elt *nfe_desc;
+  PTR *slot;
+
+  slot = htab_find_slot_with_hash (data->niters, exit,
+                                  htab_hash_pointer (exit),
+                                  INSERT);
+
+  if (!*slot)
+    {
+      nfe_desc = xmalloc (sizeof (struct nfe_cache_elt));
+      nfe_desc->exit = exit;
+      nfe_desc->valid_p = number_of_iterations_exit (data->current_loop,
+                                                    exit, &nfe_desc->niter,
+                                                    true);
+      *slot = nfe_desc;
     }
+  else
+    nfe_desc = *slot;
+
+  if (!nfe_desc->valid_p)
+    return NULL;
+
+  return &nfe_desc->niter;
+}
+
+/* Returns structure describing number of iterations determined from
+   single dominating exit of DATA->current_loop, or NULL if something
+   goes wrong.  */
+
+static struct tree_niter_desc *
+niter_for_single_dom_exit (struct ivopts_data *data)
+{
+  edge exit = single_dom_exit (data->current_loop);
+
+  if (!exit)
+    return NULL;
+
+  return niter_for_exit (data, exit);
 }
 
 /* Initializes data structures used by the iv optimization pass, stored
@@ -602,18 +749,73 @@ tree_ssa_iv_optimize_init (struct loops *loops, struct ivopts_data *data)
   unsigned i;
 
   data->version_info_size = 2 * num_ssa_names;
-  data->version_info = xcalloc (data->version_info_size,
-                               sizeof (struct version_info));
-  data->relevant = BITMAP_XMALLOC ();
+  data->version_info = XCNEWVEC (struct version_info, data->version_info_size);
+  data->relevant = BITMAP_ALLOC (NULL);
+  data->important_candidates = BITMAP_ALLOC (NULL);
   data->max_inv_id = 0;
+  data->niters = htab_create (10, nfe_hash, nfe_eq, free);
 
   for (i = 1; i < loops->num; i++)
     if (loops->parray[i])
       loops->parray[i]->aux = xcalloc (1, sizeof (struct loop_data));
 
-  VARRAY_GENERIC_PTR_NOGC_INIT (data->iv_uses, 20, "iv_uses");
-  VARRAY_GENERIC_PTR_NOGC_INIT (data->iv_candidates, 20, "iv_candidates");
-  VARRAY_GENERIC_PTR_NOGC_INIT (decl_rtl_to_reset, 20, "decl_rtl_to_reset");
+  data->iv_uses = VEC_alloc (iv_use_p, heap, 20);
+  data->iv_candidates = VEC_alloc (iv_cand_p, heap, 20);
+  decl_rtl_to_reset = VEC_alloc (tree, heap, 20);
+}
+
+/* Returns a memory object to that EXPR points.  In case we are able to
+   determine that it does not point to any such object, NULL is returned.  */
+
+static tree
+determine_base_object (tree expr)
+{
+  enum tree_code code = TREE_CODE (expr);
+  tree base, obj, op0, op1;
+
+  if (!POINTER_TYPE_P (TREE_TYPE (expr)))
+    return NULL_TREE;
+
+  switch (code)
+    {
+    case INTEGER_CST:
+      return NULL_TREE;
+
+    case ADDR_EXPR:
+      obj = TREE_OPERAND (expr, 0);
+      base = get_base_address (obj);
+
+      if (!base)
+       return expr;
+
+      if (TREE_CODE (base) == INDIRECT_REF)
+       return determine_base_object (TREE_OPERAND (base, 0));
+
+      return fold_convert (ptr_type_node,
+                          build_fold_addr_expr (base));
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      op0 = determine_base_object (TREE_OPERAND (expr, 0));
+      op1 = determine_base_object (TREE_OPERAND (expr, 1));
+      
+      if (!op1)
+       return op0;
+
+      if (!op0)
+       return (code == PLUS_EXPR
+               ? op1
+               : fold_build1 (NEGATE_EXPR, ptr_type_node, op1));
+
+      return fold_build2 (code, ptr_type_node, op0, op1);
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+      return determine_base_object (TREE_OPERAND (expr, 0));
+
+    default:
+      return fold_convert (ptr_type_node, expr);
+    }
 }
 
 /* Allocates an induction variable with given initial value BASE and step STEP
@@ -622,12 +824,13 @@ tree_ssa_iv_optimize_init (struct loops *loops, struct ivopts_data *data)
 static struct iv *
 alloc_iv (tree base, tree step)
 {
-  struct iv *iv = xcalloc (1, sizeof (struct iv));
+  struct iv *iv = XCNEW (struct iv);
 
   if (step && integer_zerop (step))
     step = NULL_TREE;
 
   iv->base = base;
+  iv->base_object = determine_base_object (base);
   iv->step = step;
   iv->biv_p = false;
   iv->have_use_for = false;
@@ -644,8 +847,7 @@ set_iv (struct ivopts_data *data, tree iv, tree base, tree step)
 {
   struct version_info *info = name_info (data, iv);
 
-  if (info->iv)
-    abort ();
+  gcc_assert (!info->iv);
 
   bitmap_set_bit (data->relevant, SSA_NAME_VERSION (iv));
   info->iv = alloc_iv (base, step);
@@ -671,38 +873,55 @@ get_iv (struct ivopts_data *data, tree var)
   return name_info (data, var)->iv;
 }
 
-/* Determines the step of a biv defined in PHI.  */
+/* Determines the step of a biv defined in PHI.  Returns NULL if PHI does
+   not define a simple affine biv with nonzero step.  */
 
 static tree
 determine_biv_step (tree phi)
 {
   struct loop *loop = bb_for_stmt (phi)->loop_father;
-  tree name = PHI_RESULT (phi), base, step;
-  tree type = TREE_TYPE (name);
+  tree name = PHI_RESULT (phi);
+  affine_iv iv;
 
   if (!is_gimple_reg (name))
     return NULL_TREE;
 
-  if (!simple_iv (loop, phi, name, &base, &step))
+  if (!simple_iv (loop, phi, name, &iv, true))
     return NULL_TREE;
 
-  if (!step)
-    return build_int_cst (type, 0);
+  return (zero_p (iv.step) ? NULL_TREE : iv.step);
+}
+
+/* Returns true if EXP is a ssa name that occurs in an abnormal phi node.  */
+
+static bool
+abnormal_ssa_name_p (tree exp)
+{
+  if (!exp)
+    return false;
+
+  if (TREE_CODE (exp) != SSA_NAME)
+    return false;
 
-  return step;
+  return SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) != 0;
 }
 
-/* Returns false if INDEX is a ssa name that occurs in an
+/* Returns false if BASE or INDEX contains a ssa name that occurs in an
    abnormal phi node.  Callback for for_each_index.  */
 
 static bool
-idx_contains_abnormal_ssa_name_p (tree base ATTRIBUTE_UNUSED, tree *index,
+idx_contains_abnormal_ssa_name_p (tree base, tree *index,
                                  void *data ATTRIBUTE_UNUSED)
 {
-  if (TREE_CODE (*index) != SSA_NAME)
-    return true;
+  if (TREE_CODE (base) == ARRAY_REF)
+    {
+      if (abnormal_ssa_name_p (TREE_OPERAND (base, 2)))
+       return false;
+      if (abnormal_ssa_name_p (TREE_OPERAND (base, 3)))
+       return false;
+    }
 
-  return SSA_NAME_OCCURS_IN_ABNORMAL_PHI (*index) == 0;
+  return !abnormal_ssa_name_p (*index);
 }
 
 /* Returns true if EXPR contains a ssa name that occurs in an
@@ -711,9 +930,15 @@ idx_contains_abnormal_ssa_name_p (tree base ATTRIBUTE_UNUSED, tree *index,
 static bool
 contains_abnormal_ssa_name_p (tree expr)
 {
-  enum tree_code code = TREE_CODE (expr);
-  char class = TREE_CODE_CLASS (code);
-    
+  enum tree_code code;
+  enum tree_code_class class;
+
+  if (!expr)
+    return false;
+
+  code = TREE_CODE (expr);
+  class = TREE_CODE_CLASS (code);
+
   if (code == SSA_NAME)
     return SSA_NAME_OCCURS_IN_ABNORMAL_PHI (expr) != 0;
 
@@ -722,26 +947,26 @@ contains_abnormal_ssa_name_p (tree expr)
     return false;
 
   if (code == ADDR_EXPR)
-    return !for_each_index (&TREE_OPERAND (expr, 1),
+    return !for_each_index (&TREE_OPERAND (expr, 0),
                            idx_contains_abnormal_ssa_name_p,
                            NULL);
 
   switch (class)
     {
-    case '2':
-    case '<':
+    case tcc_binary:
+    case tcc_comparison:
       if (contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 1)))
        return true;
 
       /* Fallthru.  */
-    case '1':
+    case tcc_unary:
       if (contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 0)))
        return true;
 
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return false;
@@ -756,31 +981,25 @@ find_bivs (struct ivopts_data *data)
   bool found = false;
   struct loop *loop = data->current_loop;
 
-  for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
     {
       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)))
        continue;
 
       step = determine_biv_step (phi);
-
       if (!step)
        continue;
-      if (cst_and_fits_in_hwi (step)
-         && int_cst_value (step) == 0)
-       continue;
 
       base = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (loop));
-      if (contains_abnormal_ssa_name_p (base))
+      base = expand_simple_operations (base);
+      if (contains_abnormal_ssa_name_p (base)
+         || contains_abnormal_ssa_name_p (step))
        continue;
 
       type = TREE_TYPE (PHI_RESULT (phi));
       base = fold_convert (type, base);
-      step = fold_convert (type, step);
-
-      /* FIXME: We do not handle induction variables whose step does
-        not satisfy cst_and_fits_in_hwi.  */
-      if (!cst_and_fits_in_hwi (step))
-       continue;
+      if (step)
+       step = fold_convert (type, step);
 
       set_iv (data, PHI_RESULT (phi), base, step);
       found = true;
@@ -799,7 +1018,7 @@ mark_bivs (struct ivopts_data *data)
   struct loop *loop = data->current_loop;
   basic_block incr_bb;
 
-  for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
     {
       iv = get_iv (data, PHI_RESULT (phi));
       if (!iv)
@@ -822,17 +1041,16 @@ mark_bivs (struct ivopts_data *data)
 }
 
 /* Checks whether STMT defines a linear induction variable and stores its
-   parameters to BASE and STEP.  */
+   parameters to IV.  */
 
 static bool
-find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt,
-                       tree *base, tree *step)
+find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, affine_iv *iv)
 {
   tree lhs;
   struct loop *loop = data->current_loop;
 
-  *base = NULL_TREE;
-  *step = NULL_TREE;
+  iv->base = NULL_TREE;
+  iv->step = NULL_TREE;
 
   if (TREE_CODE (stmt) != MODIFY_EXPR)
     return false;
@@ -841,16 +1059,12 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt,
   if (TREE_CODE (lhs) != SSA_NAME)
     return false;
 
-  if (!simple_iv (loop, stmt, TREE_OPERAND (stmt, 1), base, step))
-    return false;
-
-  /* FIXME: We do not handle induction variables whose step does
-     not satisfy cst_and_fits_in_hwi.  */
-  if (!zero_p (*step)
-      && !cst_and_fits_in_hwi (*step))
+  if (!simple_iv (loop, stmt, TREE_OPERAND (stmt, 1), iv, true))
     return false;
+  iv->base = expand_simple_operations (iv->base);
 
-  if (contains_abnormal_ssa_name_p (*base))
+  if (contains_abnormal_ssa_name_p (iv->base)
+      || contains_abnormal_ssa_name_p (iv->step))
     return false;
 
   return true;
@@ -861,12 +1075,12 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt,
 static void
 find_givs_in_stmt (struct ivopts_data *data, tree stmt)
 {
-  tree base, step;
+  affine_iv iv;
 
-  if (!find_givs_in_stmt_scev (data, stmt, &base, &step))
+  if (!find_givs_in_stmt_scev (data, stmt, &iv))
     return;
 
-  set_iv (data, TREE_OPERAND (stmt, 0), base, step);
+  set_iv (data, TREE_OPERAND (stmt, 0), iv.base, iv.step);
 }
 
 /* Finds general ivs in basic block BB.  */
@@ -894,20 +1108,6 @@ find_givs (struct ivopts_data *data)
   free (body);
 }
 
-/* Determine the number of iterations of the current loop.  */
-
-static void
-determine_number_of_iterations (struct ivopts_data *data)
-{
-  struct loop *loop = data->current_loop;
-  edge exit = single_dom_exit (loop);
-
-  if (!exit)
-    return;
-
-  number_of_iterations_exit (loop, exit, &loop_data (loop)->niter);
-}
-
 /* For each ssa name defined in LOOP determines whether it is an induction
    variable and if so, its initial value and step.  */
 
@@ -915,43 +1115,39 @@ static bool
 find_induction_variables (struct ivopts_data *data)
 {
   unsigned i;
-  struct loop *loop = data->current_loop;
+  bitmap_iterator bi;
 
   if (!find_bivs (data))
     return false;
 
   find_givs (data);
   mark_bivs (data);
-  determine_number_of_iterations (data);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      if (loop_data (loop)->niter.niter)
+      struct tree_niter_desc *niter;
+
+      niter = niter_for_single_dom_exit (data);
+
+      if (niter)
        {
          fprintf (dump_file, "  number of iterations ");
-         print_generic_expr (dump_file, loop_data (loop)->niter.niter,
-                             TDF_SLIM);
+         print_generic_expr (dump_file, niter->niter, TDF_SLIM);
          fprintf (dump_file, "\n");
 
          fprintf (dump_file, "  may be zero if ");
-         print_generic_expr (dump_file, loop_data (loop)->niter.may_be_zero,
-                             TDF_SLIM);
-         fprintf (dump_file, "\n");
-
-         fprintf (dump_file, "  bogus unless ");
-         print_generic_expr (dump_file, loop_data (loop)->niter.assumptions,
-                             TDF_SLIM);
+         print_generic_expr (dump_file, niter->may_be_zero, TDF_SLIM);
          fprintf (dump_file, "\n");
          fprintf (dump_file, "\n");
        };
  
       fprintf (dump_file, "Induction variables:\n\n");
 
-      EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i,
+      EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i, bi)
        {
          if (ver_info (data, i)->iv)
            dump_iv (dump_file, ver_info (data, i)->iv);
-       });
+       }
     }
 
   return true;
@@ -963,19 +1159,23 @@ static struct iv_use *
 record_use (struct ivopts_data *data, tree *use_p, struct iv *iv,
            tree stmt, enum use_type use_type)
 {
-  struct iv_use *use = xcalloc (1, sizeof (struct iv_use));
+  struct iv_use *use = XCNEW (struct iv_use);
 
   use->id = n_iv_uses (data);
   use->type = use_type;
   use->iv = iv;
   use->stmt = stmt;
   use->op_p = use_p;
-  use->related_cands = BITMAP_XMALLOC ();
+  use->related_cands = BITMAP_ALLOC (NULL);
+
+  /* To avoid showing ssa name in the dumps, if it was not reset by the
+     caller.  */
+  iv->ssa_name = NULL_TREE;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     dump_use (dump_file, use);
 
-  VARRAY_PUSH_GENERIC_PTR_NOGC (data->iv_uses, use);
+  VEC_safe_push (iv_use_p, heap, data->iv_uses, use);
 
   return use;
 }
@@ -1030,9 +1230,8 @@ find_interesting_uses_outer_or_nonlin (struct ivopts_data *data, tree op,
     {
       use = iv_use (data, iv->use_id);
 
-      if (use->type != USE_NONLINEAR_EXPR
-         && use->type != USE_OUTER)
-       abort ();
+      gcc_assert (use->type == USE_NONLINEAR_EXPR
+                 || use->type == USE_OUTER);
 
       if (type == USE_NONLINEAR_EXPR)
        use->type = USE_NONLINEAR_EXPR;
@@ -1046,13 +1245,12 @@ find_interesting_uses_outer_or_nonlin (struct ivopts_data *data, tree op,
     }
   iv->have_use_for = true;
 
-  civ = xmalloc (sizeof (struct iv));
+  civ = XNEW (struct iv);
   *civ = *iv;
 
   stmt = SSA_NAME_DEF_STMT (op);
-  if (TREE_CODE (stmt) != PHI_NODE
-      && TREE_CODE (stmt) != MODIFY_EXPR)
-    abort ();
+  gcc_assert (TREE_CODE (stmt) == PHI_NODE
+             || TREE_CODE (stmt) == MODIFY_EXPR);
 
   use = record_use (data, NULL, civ, stmt, type);
   iv->use_id = use->id;
@@ -1091,8 +1289,8 @@ find_interesting_uses_cond (struct ivopts_data *data, tree stmt, tree *cond_p)
 
   const_iv.step = NULL_TREE;
 
-  if (integer_zerop (*cond_p)
-      || integer_nonzerop (*cond_p))
+  if (TREE_CODE (*cond_p) != SSA_NAME
+      && !COMPARISON_CLASS_P (*cond_p))
     return;
 
   if (TREE_CODE (*cond_p) == SSA_NAME)
@@ -1134,11 +1332,44 @@ find_interesting_uses_cond (struct ivopts_data *data, tree stmt, tree *cond_p)
       return;
     }
 
-  civ = xmalloc (sizeof (struct iv));
+  civ = XNEW (struct iv);
   *civ = zero_p (iv0->step) ? *iv1: *iv0;
   record_use (data, cond_p, civ, stmt, USE_COMPARE);
 }
 
+/* Returns true if expression EXPR is obviously invariant in LOOP,
+   i.e. if all its operands are defined outside of the LOOP.  */
+
+bool
+expr_invariant_in_loop_p (struct loop *loop, tree expr)
+{
+  basic_block def_bb;
+  unsigned i, len;
+
+  if (is_gimple_min_invariant (expr))
+    return true;
+
+  if (TREE_CODE (expr) == SSA_NAME)
+    {
+      def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (expr));
+      if (def_bb
+         && flow_bb_inside_loop_p (loop, def_bb))
+       return false;
+
+      return true;
+    }
+
+  if (!EXPR_P (expr))
+    return false;
+
+  len = TREE_CODE_LENGTH (TREE_CODE (expr));
+  for (i = 0; i < len; i++)
+    if (!expr_invariant_in_loop_p (loop, TREE_OPERAND (expr, i)))
+      return false;
+
+  return true;
+}
+
 /* Cumulates the steps of indices into DATA and replaces their values with the
    initial ones.  Returns false when the value of the index cannot be determined.
    Callback for for_each_index.  */
@@ -1155,8 +1386,35 @@ idx_find_step (tree base, tree *idx, void *data)
 {
   struct ifs_ivopts_data *dta = data;
   struct iv *iv;
-  tree step, type, iv_type, iv_step;
-  
+  tree step, iv_step, lbound, off;
+  struct loop *loop = dta->ivopts_data->current_loop;
+
+  if (TREE_CODE (base) == MISALIGNED_INDIRECT_REF
+      || TREE_CODE (base) == ALIGN_INDIRECT_REF)
+    return false;
+
+  /* If base is a component ref, require that the offset of the reference
+     be invariant.  */
+  if (TREE_CODE (base) == COMPONENT_REF)
+    {
+      off = component_ref_field_offset (base);
+      return expr_invariant_in_loop_p (loop, off);
+    }
+
+  /* If base is array, first check whether we will be able to move the
+     reference out of the loop (in order to take its address in strength
+     reduction).  In order for this to work we need both lower bound
+     and step to be loop invariants.  */
+  if (TREE_CODE (base) == ARRAY_REF)
+    {
+      step = array_ref_element_size (base);
+      lbound = array_ref_low_bound (base);
+
+      if (!expr_invariant_in_loop_p (loop, step)
+         || !expr_invariant_in_loop_p (loop, lbound))
+       return false;
+    }
+
   if (TREE_CODE (*idx) != SSA_NAME)
     return true;
 
@@ -1169,19 +1427,22 @@ idx_find_step (tree base, tree *idx, void *data)
   if (!iv->step)
     return true;
 
-  iv_type = TREE_TYPE (iv->base);
-  type = build_pointer_type (TREE_TYPE (base));
   if (TREE_CODE (base) == ARRAY_REF)
-    step = array_ref_element_size (base);
+    {
+      step = array_ref_element_size (base);
+
+      /* We only handle addresses whose step is an integer constant.  */
+      if (TREE_CODE (step) != INTEGER_CST)
+       return false;
+    }
   else
     /* The step for pointer arithmetics already is 1 byte.  */
-    step = build_int_cst (type, 1);
+    step = build_int_cst (sizetype, 1);
 
-  if (TYPE_PRECISION (iv_type) < TYPE_PRECISION (type))
-    iv_step = can_count_iv_in_wider_type (dta->ivopts_data->current_loop,
-                                         type, iv->base, iv->step, dta->stmt);
-  else
-    iv_step = fold_convert (iv_type, iv->step);
+  /* FIXME: convert_step should not be used outside chrec_convert: fix
+     this by calling chrec_convert.  */
+  iv_step = convert_step (dta->ivopts_data->current_loop,
+                         sizetype, iv->base, iv->step, dta->stmt);
 
   if (!iv_step)
     {
@@ -1189,12 +1450,12 @@ idx_find_step (tree base, tree *idx, void *data)
       return false;
     }
 
-  step = EXEC_BINARY (MULT_EXPR, type, step, iv_step);
+  step = fold_build2 (MULT_EXPR, sizetype, step, iv_step);
 
   if (!*dta->step_p)
     *dta->step_p = step;
   else
-    *dta->step_p = EXEC_BINARY (PLUS_EXPR, type, *dta->step_p, step);
+    *dta->step_p = fold_build2 (PLUS_EXPR, sizetype, *dta->step_p, step);
 
   return true;
 }
@@ -1203,39 +1464,135 @@ idx_find_step (tree base, tree *idx, void *data)
    object is passed to it in DATA.  */
 
 static bool
-idx_record_use (tree base ATTRIBUTE_UNUSED, tree *idx,
+idx_record_use (tree base, tree *idx,
                void *data)
 {
   find_interesting_uses_op (data, *idx);
+  if (TREE_CODE (base) == ARRAY_REF)
+    {
+      find_interesting_uses_op (data, array_ref_element_size (base));
+      find_interesting_uses_op (data, array_ref_low_bound (base));
+    }
   return true;
 }
 
+/* Returns true if memory reference REF may be unaligned.  */
+
+static bool
+may_be_unaligned_p (tree ref)
+{
+  tree base;
+  tree base_type;
+  HOST_WIDE_INT bitsize;
+  HOST_WIDE_INT bitpos;
+  tree toffset;
+  enum machine_mode mode;
+  int unsignedp, volatilep;
+  unsigned base_align;
+
+  /* TARGET_MEM_REFs are translated directly to valid MEMs on the target,
+     thus they are not misaligned.  */
+  if (TREE_CODE (ref) == TARGET_MEM_REF)
+    return false;
+
+  /* The test below is basically copy of what expr.c:normal_inner_ref
+     does to check whether the object must be loaded by parts when
+     STRICT_ALIGNMENT is true.  */
+  base = get_inner_reference (ref, &bitsize, &bitpos, &toffset, &mode,
+                             &unsignedp, &volatilep, true);
+  base_type = TREE_TYPE (base);
+  base_align = TYPE_ALIGN (base_type);
+
+  if (mode != BLKmode
+      && (base_align < GET_MODE_ALIGNMENT (mode)
+         || bitpos % GET_MODE_ALIGNMENT (mode) != 0
+         || bitpos % BITS_PER_UNIT != 0))
+    return true;
+
+  return false;
+}
+
 /* Finds addresses in *OP_P inside STMT.  */
 
 static void
 find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
 {
-  tree base = unshare_expr (*op_p), step = NULL;
+  tree base = *op_p, step = NULL;
   struct iv *civ;
   struct ifs_ivopts_data ifs_ivopts_data;
 
+  /* Do not play with volatile memory references.  A bit too conservative,
+     perhaps, but safe.  */
+  if (stmt_ann (stmt)->has_volatile_ops)
+    goto fail;
+
   /* Ignore bitfields for now.  Not really something terribly complicated
      to handle.  TODO.  */
   if (TREE_CODE (base) == COMPONENT_REF
       && DECL_NONADDRESSABLE_P (TREE_OPERAND (base, 1)))
     goto fail;
 
-  ifs_ivopts_data.ivopts_data = data;
-  ifs_ivopts_data.stmt = stmt;
-  ifs_ivopts_data.step_p = &step;
-  if (!for_each_index (&base, idx_find_step, &ifs_ivopts_data)
-      || zero_p (step))
+  if (STRICT_ALIGNMENT
+      && may_be_unaligned_p (base))
     goto fail;
 
-  if (TREE_CODE (base) == INDIRECT_REF)
-    base = TREE_OPERAND (base, 0);
+  base = unshare_expr (base);
+
+  if (TREE_CODE (base) == TARGET_MEM_REF)
+    {
+      tree type = build_pointer_type (TREE_TYPE (base));
+      tree astep;
+
+      if (TMR_BASE (base)
+         && TREE_CODE (TMR_BASE (base)) == SSA_NAME)
+       {
+         civ = get_iv (data, TMR_BASE (base));
+         if (!civ)
+           goto fail;
+
+         TMR_BASE (base) = civ->base;
+         step = civ->step;
+       }
+      if (TMR_INDEX (base)
+         && TREE_CODE (TMR_INDEX (base)) == SSA_NAME)
+       {
+         civ = get_iv (data, TMR_INDEX (base));
+         if (!civ)
+           goto fail;
+
+         TMR_INDEX (base) = civ->base;
+         astep = civ->step;
+
+         if (astep)
+           {
+             if (TMR_STEP (base))
+               astep = fold_build2 (MULT_EXPR, type, TMR_STEP (base), astep);
+
+             if (step)
+               step = fold_build2 (PLUS_EXPR, type, step, astep);
+             else
+               step = astep;
+           }
+       }
+
+      if (zero_p (step))
+       goto fail;
+      base = tree_mem_ref_addr (type, base);
+    }
   else
-    base = build_addr (base);
+    {
+      ifs_ivopts_data.ivopts_data = data;
+      ifs_ivopts_data.stmt = stmt;
+      ifs_ivopts_data.step_p = &step;
+      if (!for_each_index (&base, idx_find_step, &ifs_ivopts_data)
+         || zero_p (step))
+       goto fail;
+
+      gcc_assert (TREE_CODE (base) != ALIGN_INDIRECT_REF);
+      gcc_assert (TREE_CODE (base) != MISALIGNED_INDIRECT_REF);
+
+      base = build_fold_addr_expr (base);
+    }
 
   civ = alloc_iv (base, step);
   record_use (data, op_p, civ, stmt, USE_ADDRESS);
@@ -1250,26 +1607,13 @@ fail:
 static void
 find_invariants_stmt (struct ivopts_data *data, tree stmt)
 {
-  use_optype uses = NULL;
-  unsigned i, n;
+  ssa_op_iter iter;
+  use_operand_p use_p;
   tree op;
 
-  if (TREE_CODE (stmt) == PHI_NODE)
-    n = PHI_NUM_ARGS (stmt);
-  else
-    {
-      get_stmt_operands (stmt);
-      uses = STMT_USE_OPS (stmt);
-      n = NUM_USES (uses);
-    }
-
-  for (i = 0; i < n; i++)
+  FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
     {
-      if (TREE_CODE (stmt) == PHI_NODE)
-       op = PHI_ARG_DEF (stmt, i);
-      else
-       op = USE_OP (uses, i);
-
+      op = USE_FROM_PTR (use_p);
       record_invariant (data, op, false);
     }
 }
@@ -1281,8 +1625,8 @@ find_interesting_uses_stmt (struct ivopts_data *data, tree stmt)
 {
   struct iv *iv;
   tree op, lhs, rhs;
-  use_optype uses = NULL;
-  unsigned i, n;
+  ssa_op_iter iter;
+  use_operand_p use_p;
 
   find_invariants_stmt (data, stmt);
 
@@ -1310,25 +1654,34 @@ find_interesting_uses_stmt (struct ivopts_data *data, tree stmt)
 
       switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
        {
-       case '<':
+       case tcc_comparison:
          find_interesting_uses_cond (data, stmt, &TREE_OPERAND (stmt, 1));
          return;
 
-       case 'r':
+       case tcc_reference:
          find_interesting_uses_address (data, stmt, &TREE_OPERAND (stmt, 1));
-         if (TREE_CODE_CLASS (TREE_CODE (lhs)) == 'r')
+         if (REFERENCE_CLASS_P (lhs))
            find_interesting_uses_address (data, stmt, &TREE_OPERAND (stmt, 0));
          return;
 
        default: ;
        }
 
-      if (TREE_CODE_CLASS (TREE_CODE (lhs)) == 'r')
+      if (REFERENCE_CLASS_P (lhs)
+         && is_gimple_val (rhs))
        {
          find_interesting_uses_address (data, stmt, &TREE_OPERAND (stmt, 0));
          find_interesting_uses_op (data, rhs);
          return;
        }
+
+      /* TODO -- we should also handle address uses of type
+
+        memory = call (whatever);
+
+        and
+
+        call (memory).  */
     }
 
   if (TREE_CODE (stmt) == PHI_NODE
@@ -1341,20 +1694,9 @@ find_interesting_uses_stmt (struct ivopts_data *data, tree stmt)
        return;
     }
 
-  if (TREE_CODE (stmt) == PHI_NODE)
-    n = PHI_NUM_ARGS (stmt);
-  else
-    {
-      uses = STMT_USE_OPS (stmt);
-      n = NUM_USES (uses);
-    }
-
-  for (i = 0; i < n; i++)
+  FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
     {
-      if (TREE_CODE (stmt) == PHI_NODE)
-       op = PHI_ARG_DEF (stmt, i);
-      else
-       op = USE_OP (uses, i);
+      op = USE_FROM_PTR (use_p);
 
       if (TREE_CODE (op) != SSA_NAME)
        continue;
@@ -1375,7 +1717,7 @@ find_interesting_uses_outside (struct ivopts_data *data, edge exit)
 {
   tree phi, def;
 
-  for (phi = phi_nodes (exit->dest); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (exit->dest); phi; phi = PHI_CHAIN (phi))
     {
       def = PHI_ARG_DEF_FROM_EDGE (phi, exit);
       find_interesting_uses_outer (data, def);
@@ -1400,14 +1742,15 @@ find_interesting_uses (struct ivopts_data *data)
 
   for (i = 0; i < data->current_loop->num_nodes; i++)
     {
+      edge_iterator ei;
       bb = body[i];
 
-      for (e = bb->succ; e; e = e->succ_next)
+      FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->dest != EXIT_BLOCK_PTR
            && !flow_bb_inside_loop_p (data->current_loop, e->dest))
          find_interesting_uses_outside (data, e);
 
-      for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
        find_interesting_uses_stmt (data, phi);
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
        find_interesting_uses_stmt (data, bsi_stmt (bsi));
@@ -1415,9 +1758,11 @@ find_interesting_uses (struct ivopts_data *data)
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
+      bitmap_iterator bi;
+
       fprintf (dump_file, "\n");
 
-      EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i,
+      EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i, bi)
        {
          info = ver_info (data, i);
          if (info->inv_id)
@@ -1427,7 +1772,7 @@ find_interesting_uses (struct ivopts_data *data)
              fprintf (dump_file, " is invariant (%d)%s\n",
                       info->inv_id, info->has_nonlin_use ? "" : ", eliminable");
            }
-       });
+       }
 
       fprintf (dump_file, "\n");
     }
@@ -1435,26 +1780,213 @@ find_interesting_uses (struct ivopts_data *data)
   free (body);
 }
 
-/* Adds a candidate BASE + STEP * i.  Important field is set to IMPORTANT and
-   position to POS.  If USE is not NULL, the candidate is set as related to
-   it.  If both BASE and STEP are NULL, we add a pseudocandidate for the
-   replacement of the final value of the iv by a direct computation.  */
+/* Strips constant offsets from EXPR and stores them to OFFSET.  If INSIDE_ADDR
+   is true, assume we are inside an address.  If TOP_COMPREF is true, assume
+   we are at the top-level of the processed address.  */
 
-static struct iv_cand *
-add_candidate_1 (struct ivopts_data *data,
-                tree base, tree step, bool important, enum iv_position pos,
+static tree
+strip_offset_1 (tree expr, bool inside_addr, bool top_compref,
+               unsigned HOST_WIDE_INT *offset)
+{
+  tree op0 = NULL_TREE, op1 = NULL_TREE, tmp, step;
+  enum tree_code code;
+  tree type, orig_type = TREE_TYPE (expr);
+  unsigned HOST_WIDE_INT off0, off1, st;
+  tree orig_expr = expr;
+
+  STRIP_NOPS (expr);
+
+  type = TREE_TYPE (expr);
+  code = TREE_CODE (expr);
+  *offset = 0;
+
+  switch (code)
+    {
+    case INTEGER_CST:
+      if (!cst_and_fits_in_hwi (expr)
+         || zero_p (expr))
+       return orig_expr;
+
+      *offset = int_cst_value (expr);
+      return build_int_cst_type (orig_type, 0);
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      op0 = TREE_OPERAND (expr, 0);
+      op1 = TREE_OPERAND (expr, 1);
+
+      op0 = strip_offset_1 (op0, false, false, &off0);
+      op1 = strip_offset_1 (op1, false, false, &off1);
+
+      *offset = (code == PLUS_EXPR ? off0 + off1 : off0 - off1);
+      if (op0 == TREE_OPERAND (expr, 0)
+         && op1 == TREE_OPERAND (expr, 1))
+       return orig_expr;
+
+      if (zero_p (op1))
+       expr = op0;
+      else if (zero_p (op0))
+       {
+         if (code == PLUS_EXPR)
+           expr = op1;
+         else
+           expr = fold_build1 (NEGATE_EXPR, type, op1);
+       }
+      else
+       expr = fold_build2 (code, type, op0, op1);
+
+      return fold_convert (orig_type, expr);
+
+    case ARRAY_REF:
+      if (!inside_addr)
+       return orig_expr;
+
+      step = array_ref_element_size (expr);
+      if (!cst_and_fits_in_hwi (step))
+       break;
+
+      st = int_cst_value (step);
+      op1 = TREE_OPERAND (expr, 1);
+      op1 = strip_offset_1 (op1, false, false, &off1);
+      *offset = off1 * st;
+
+      if (top_compref
+         && zero_p (op1))
+       {
+         /* Strip the component reference completely.  */
+         op0 = TREE_OPERAND (expr, 0);
+         op0 = strip_offset_1 (op0, inside_addr, top_compref, &off0);
+         *offset += off0;
+         return op0;
+       }
+      break;
+
+    case COMPONENT_REF:
+      if (!inside_addr)
+       return orig_expr;
+
+      tmp = component_ref_field_offset (expr);
+      if (top_compref
+         && cst_and_fits_in_hwi (tmp))
+       {
+         /* Strip the component reference completely.  */
+         op0 = TREE_OPERAND (expr, 0);
+         op0 = strip_offset_1 (op0, inside_addr, top_compref, &off0);
+         *offset = off0 + int_cst_value (tmp);
+         return op0;
+       }
+      break;
+
+    case ADDR_EXPR:
+      op0 = TREE_OPERAND (expr, 0);
+      op0 = strip_offset_1 (op0, true, true, &off0);
+      *offset += off0;
+
+      if (op0 == TREE_OPERAND (expr, 0))
+       return orig_expr;
+
+      expr = build_fold_addr_expr (op0);
+      return fold_convert (orig_type, expr);
+
+    case INDIRECT_REF:
+      inside_addr = false;
+      break;
+
+    default:
+      return orig_expr;
+    }
+
+  /* Default handling of expressions for that we want to recurse into
+     the first operand.  */
+  op0 = TREE_OPERAND (expr, 0);
+  op0 = strip_offset_1 (op0, inside_addr, false, &off0);
+  *offset += off0;
+
+  if (op0 == TREE_OPERAND (expr, 0)
+      && (!op1 || op1 == TREE_OPERAND (expr, 1)))
+    return orig_expr;
+
+  expr = copy_node (expr);
+  TREE_OPERAND (expr, 0) = op0;
+  if (op1)
+    TREE_OPERAND (expr, 1) = op1;
+
+  /* Inside address, we might strip the top level component references,
+     thus changing type of the expression.  Handling of ADDR_EXPR
+     will fix that.  */
+  expr = fold_convert (orig_type, expr);
+
+  return expr;
+}
+
+/* Strips constant offsets from EXPR and stores them to OFFSET.  */
+
+static tree
+strip_offset (tree expr, unsigned HOST_WIDE_INT *offset)
+{
+  return strip_offset_1 (expr, false, false, offset);
+}
+
+/* Returns variant of TYPE that can be used as base for different uses.
+   For integer types, we return unsigned variant of the type, which
+   avoids problems with overflows.  For pointer types, we return void *.  */
+
+static tree
+generic_type_for (tree type)
+{
+  if (POINTER_TYPE_P (type))
+    return ptr_type_node;
+
+  if (TYPE_UNSIGNED (type))
+    return type;
+
+  return unsigned_type_for (type);
+}
+
+/* Records invariants in *EXPR_P.  Callback for walk_tree.  DATA contains
+   the bitmap to that we should store it.  */
+
+static struct ivopts_data *fd_ivopts_data;
+static tree
+find_depends (tree *expr_p, int *ws ATTRIBUTE_UNUSED, void *data)
+{
+  bitmap *depends_on = data;
+  struct version_info *info;
+
+  if (TREE_CODE (*expr_p) != SSA_NAME)
+    return NULL_TREE;
+  info = name_info (fd_ivopts_data, *expr_p);
+
+  if (!info->inv_id || info->has_nonlin_use)
+    return NULL_TREE;
+
+  if (!*depends_on)
+    *depends_on = BITMAP_ALLOC (NULL);
+  bitmap_set_bit (*depends_on, info->inv_id);
+
+  return NULL_TREE;
+}
+
+/* Adds a candidate BASE + STEP * i.  Important field is set to IMPORTANT and
+   position to POS.  If USE is not NULL, the candidate is set as related to
+   it.  If both BASE and STEP are NULL, we add a pseudocandidate for the
+   replacement of the final value of the iv by a direct computation.  */
+
+static struct iv_cand *
+add_candidate_1 (struct ivopts_data *data,
+                tree base, tree step, bool important, enum iv_position pos,
                 struct iv_use *use, tree incremented_at)
 {
   unsigned i;
   struct iv_cand *cand = NULL;
-  tree type;
+  tree type, orig_type;
   
   if (base)
     {
-      type = TREE_TYPE (base);
-      if (!TYPE_UNSIGNED (type))
+      orig_type = TREE_TYPE (base);
+      type = generic_type_for (orig_type);
+      if (type != orig_type)
        {
-         type = unsigned_type_for (type);
          base = fold_convert (type, base);
          if (step)
            step = fold_convert (type, step);
@@ -1499,7 +2031,7 @@ add_candidate_1 (struct ivopts_data *data,
 
   if (i == n_iv_cands (data))
     {
-      cand = xcalloc (1, sizeof (struct iv_cand));
+      cand = XCNEW (struct iv_cand);
       cand->id = i;
 
       if (!base && !step)
@@ -1515,7 +2047,14 @@ add_candidate_1 (struct ivopts_data *data,
        }
       cand->important = important;
       cand->incremented_at = incremented_at;
-      VARRAY_PUSH_GENERIC_PTR_NOGC (data->iv_candidates, cand);
+      VEC_safe_push (iv_cand_p, heap, data->iv_candidates, cand);
+
+      if (step
+         && TREE_CODE (step) != INTEGER_CST)
+       {
+         fd_ivopts_data = data;
+         walk_tree (&step, find_depends, &cand->depends_on, NULL);
+       }
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        dump_cand (dump_file, cand);
@@ -1539,6 +2078,27 @@ add_candidate_1 (struct ivopts_data *data,
   return cand;
 }
 
+/* Returns true if incrementing the induction variable at the end of the LOOP
+   is allowed.
+
+   The purpose is to avoid splitting latch edge with a biv increment, thus
+   creating a jump, possibly confusing other optimization passes and leaving
+   less freedom to scheduler.  So we allow IP_END_POS only if IP_NORMAL_POS
+   is not available (so we do not have a better alternative), or if the latch
+   edge is already nonempty.  */
+
+static bool
+allow_ip_end_pos_p (struct loop *loop)
+{
+  if (!ip_normal_pos (loop))
+    return true;
+
+  if (!empty_block_p (ip_end_pos (loop)))
+    return true;
+
+  return false;
+}
+
 /* Adds a candidate BASE + STEP * i.  Important field is set to IMPORTANT and
    position to POS.  If USE is not NULL, the candidate is set as related to
    it.  The candidate computation is scheduled on all available positions.  */
@@ -1549,27 +2109,33 @@ add_candidate (struct ivopts_data *data,
 {
   if (ip_normal_pos (data->current_loop))
     add_candidate_1 (data, base, step, important, IP_NORMAL, use, NULL_TREE);
-  if (ip_end_pos (data->current_loop))
+  if (ip_end_pos (data->current_loop)
+      && allow_ip_end_pos_p (data->current_loop))
     add_candidate_1 (data, base, step, important, IP_END, use, NULL_TREE);
 }
 
+/* Add a standard "0 + 1 * iteration" iv candidate for a
+   type with SIZE bits.  */
+
+static void
+add_standard_iv_candidates_for_size (struct ivopts_data *data,
+                                    unsigned int size)
+{
+  tree type = lang_hooks.types.type_for_size (size, true);
+  add_candidate (data, build_int_cst (type, 0), build_int_cst (type, 1),
+                true, NULL);
+}
+
 /* Adds standard iv candidates.  */
 
 static void
 add_standard_iv_candidates (struct ivopts_data *data)
 {
-  /* Add 0 + 1 * iteration candidate.  */
-  add_candidate (data,
-                build_int_cst (unsigned_intSI_type_node, 0),
-                build_int_cst (unsigned_intSI_type_node, 1),
-                true, NULL);
+  add_standard_iv_candidates_for_size (data, INT_TYPE_SIZE);
 
-  /* The same for a long type if it is still fast enought.  */
-  if (BITS_PER_WORD > 32)
-    add_candidate (data,
-                  build_int_cst (unsigned_intDI_type_node, 0),
-                  build_int_cst (unsigned_intDI_type_node, 1),
-                  true, NULL);
+  /* The same for a double-integer type if it is still fast enough.  */
+  if (BITS_PER_WORD >= INT_TYPE_SIZE * 2)
+    add_standard_iv_candidates_for_size (data, INT_TYPE_SIZE * 2);
 }
 
 
@@ -1609,13 +2175,14 @@ add_old_ivs_candidates (struct ivopts_data *data)
 {
   unsigned i;
   struct iv *iv;
+  bitmap_iterator bi;
 
-  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i,
+  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i, bi)
     {
       iv = ver_info (data, i)->iv;
       if (iv && iv->biv_p && !zero_p (iv->step))
        add_old_iv_candidates (data, iv);
-    });
+    }
 }
 
 /* Adds candidates based on the value of the induction variable IV and USE.  */
@@ -1624,65 +2191,21 @@ static void
 add_iv_value_candidates (struct ivopts_data *data,
                         struct iv *iv, struct iv_use *use)
 {
+  unsigned HOST_WIDE_INT offset;
+  tree base;
+
   add_candidate (data, iv->base, iv->step, false, use);
 
-  /* The same, but with initial value zero.  */
+  /* The same, but with initial value zero.  Make such variable important,
+     since it is generic enough so that possibly many uses may be based
+     on it.  */
   add_candidate (data, build_int_cst (TREE_TYPE (iv->base), 0),
-                iv->step, false, use);
-}
-
-/* Adds candidates based on the address IV and USE.  */
-
-static void
-add_address_candidates (struct ivopts_data *data,
-                       struct iv *iv, struct iv_use *use)
-{
-  tree base, abase, tmp, *act;
-
-  /* First, the trivial choices.  */
-  add_iv_value_candidates (data, iv, use);
-
-  /* Second, try removing the COMPONENT_REFs.  */
-  if (TREE_CODE (iv->base) == ADDR_EXPR)
-    {
-      base = TREE_OPERAND (iv->base, 0);
-      while (TREE_CODE (base) == COMPONENT_REF
-            || (TREE_CODE (base) == ARRAY_REF
-                && TREE_CODE (TREE_OPERAND (base, 1)) == INTEGER_CST))
-       base = TREE_OPERAND (base, 0);
-
-      if (base != TREE_OPERAND (iv->base, 0))
-       { 
-         if (TREE_CODE (base) == INDIRECT_REF)
-           base = TREE_OPERAND (base, 0);
-         else
-           base = build_addr (base);
-         add_candidate (data, base, iv->step, false, use);
-       }
-    }
+                iv->step, true, use);
 
   /* Third, try removing the constant offset.  */
-  abase = iv->base;
-  while (TREE_CODE (abase) == PLUS_EXPR
-        && TREE_CODE (TREE_OPERAND (abase, 1)) != INTEGER_CST)
-    abase = TREE_OPERAND (abase, 0);
-  /* We found the offset, so make the copy of the non-shared part and
-     remove it.  */
-  if (TREE_CODE (abase) == PLUS_EXPR)
-    {
-      tmp = iv->base;
-      act = &base;
-
-      for (tmp = iv->base; tmp != abase; tmp = TREE_OPERAND (tmp, 0))
-       {
-         *act = build2 (PLUS_EXPR, TREE_TYPE (tmp),
-                        NULL_TREE, TREE_OPERAND (tmp, 1));
-         act = &TREE_OPERAND (*act, 0);
-       }
-      *act = TREE_OPERAND (tmp, 0);
-
-      add_candidate (data, base, iv->step, false, use);
-    }
+  base = strip_offset (iv->base, &offset);
+  if (offset)
+    add_candidate (data, base, iv->step, false, use);
 }
 
 /* Possibly adds pseudocandidate for replacing the final value of USE by
@@ -1692,16 +2215,11 @@ static void
 add_iv_outer_candidates (struct ivopts_data *data, struct iv_use *use)
 {
   struct tree_niter_desc *niter;
-  struct loop *loop = data->current_loop;
 
   /* We must know where we exit the loop and how many times does it roll.  */
-  if (!single_dom_exit (loop))
-    return;
-
-  niter = &loop_data (loop)->niter;
-  if (!niter->niter
-      || !operand_equal_p (niter->assumptions, boolean_true_node, 0)
-      || !operand_equal_p (niter->may_be_zero, boolean_false_node, 0))
+  niter = niter_for_single_dom_exit (data);
+  if (!niter
+      || !zero_p (niter->may_be_zero))
     return;
 
   add_candidate_1 (data, NULL, NULL, false, IP_NORMAL, use, NULL_TREE);
@@ -1725,6 +2243,7 @@ add_derived_ivs_candidates (struct ivopts_data *data)
        {
        case USE_NONLINEAR_EXPR:
        case USE_COMPARE:
+       case USE_ADDRESS:
          /* Just add the ivs based on the value of the iv used here.  */
          add_iv_value_candidates (data, use->iv, use);
          break;
@@ -1737,14 +2256,49 @@ add_derived_ivs_candidates (struct ivopts_data *data)
          add_iv_outer_candidates (data, use);
          break;
 
-       case USE_ADDRESS:
-         add_address_candidates (data, use->iv, use);
-         break;
-
        default:
-         abort ();
+         gcc_unreachable ();
+       }
+    }
+}
+
+/* Record important candidates and add them to related_cands bitmaps
+   if needed.  */
+
+static void
+record_important_candidates (struct ivopts_data *data)
+{
+  unsigned i;
+  struct iv_use *use;
+
+  for (i = 0; i < n_iv_cands (data); i++)
+    {
+      struct iv_cand *cand = iv_cand (data, i);
+
+      if (cand->important)
+       bitmap_set_bit (data->important_candidates, i);
+    }
+
+  data->consider_all_candidates = (n_iv_cands (data)
+                                  <= CONSIDER_ALL_CANDIDATES_BOUND);
+
+  if (data->consider_all_candidates)
+    {
+      /* We will not need "related_cands" bitmaps in this case,
+        so release them to decrease peak memory consumption.  */
+      for (i = 0; i < n_iv_uses (data); i++)
+       {
+         use = iv_use (data, i);
+         BITMAP_FREE (use->related_cands);
        }
     }
+  else
+    {
+      /* Add important candidates to the related_cands bitmaps.  */
+      for (i = 0; i < n_iv_uses (data); i++)
+       bitmap_ior_into (iv_use (data, i)->related_cands,
+                        data->important_candidates);
+    }
 }
 
 /* Finds the candidates for the induction variables.  */
@@ -1760,6 +2314,9 @@ find_iv_candidates (struct ivopts_data *data)
 
   /* Add induction variables derived from uses.  */
   add_derived_ivs_candidates (data);
+
+  /* Record the important candidates.  */
+  record_important_candidates (data);
 }
 
 /* Allocates the data structure mapping the (use, candidate) pairs to costs.
@@ -1769,51 +2326,48 @@ find_iv_candidates (struct ivopts_data *data)
 static void
 alloc_use_cost_map (struct ivopts_data *data)
 {
-  unsigned i, n_imp = 0, size, j;
-
-  if (!data->consider_all_candidates)
-    {
-      for (i = 0; i < n_iv_cands (data); i++)
-       {
-         struct iv_cand *cand = iv_cand (data, i);
-         if (cand->important)
-           n_imp++;
-       }
-    }
+  unsigned i, size, s, j;
 
   for (i = 0; i < n_iv_uses (data); i++)
     {
       struct iv_use *use = iv_use (data, i);
+      bitmap_iterator bi;
 
       if (data->consider_all_candidates)
-       {
-         size = n_iv_cands (data);
-         use->n_map_members = size;
-       }
+       size = n_iv_cands (data);
       else
        {
-         size = n_imp;
-         EXECUTE_IF_SET_IN_BITMAP (use->related_cands, 0, j, size++);
-         use->n_map_members = 0;
+         s = 0;
+         EXECUTE_IF_SET_IN_BITMAP (use->related_cands, 0, j, bi)
+           {
+             s++;
+           }
+
+         /* Round up to the power of two, so that moduling by it is fast.  */
+         for (size = 1; size < s; size <<= 1)
+           continue;
        }
 
-      use->cost_map = xcalloc (size, sizeof (struct cost_pair));
+      use->n_map_members = size;
+      use->cost_map = XCNEWVEC (struct cost_pair, size);
     }
 }
 
 /* Sets cost of (USE, CANDIDATE) pair to COST and record that it depends
-   on invariants DEPENDS_ON.  */
+   on invariants DEPENDS_ON and that the value used in expressing it
+   is VALUE.*/
 
 static void
 set_use_iv_cost (struct ivopts_data *data,
                 struct iv_use *use, struct iv_cand *cand, unsigned cost,
-                bitmap depends_on)
+                bitmap depends_on, tree value)
 {
-  if (cost == INFTY
-      && depends_on)
+  unsigned i, s;
+
+  if (cost == INFTY)
     {
-      BITMAP_XFREE (depends_on);
-      depends_on = NULL;
+      BITMAP_FREE (depends_on);
+      return;
     }
 
   if (data->consider_all_candidates)
@@ -1821,45 +2375,60 @@ set_use_iv_cost (struct ivopts_data *data,
       use->cost_map[cand->id].cand = cand;
       use->cost_map[cand->id].cost = cost;
       use->cost_map[cand->id].depends_on = depends_on;
+      use->cost_map[cand->id].value = value;
       return;
     }
 
-  if (cost == INFTY)
-    return;
-
-  use->cost_map[use->n_map_members].cand = cand;
-  use->cost_map[use->n_map_members].cost = cost;
-  use->cost_map[use->n_map_members].depends_on = depends_on;
-  use->n_map_members++;
+  /* n_map_members is a power of two, so this computes modulo.  */
+  s = cand->id & (use->n_map_members - 1);
+  for (i = s; i < use->n_map_members; i++)
+    if (!use->cost_map[i].cand)
+      goto found;
+  for (i = 0; i < s; i++)
+    if (!use->cost_map[i].cand)
+      goto found;
+
+  gcc_unreachable ();
+
+found:
+  use->cost_map[i].cand = cand;
+  use->cost_map[i].cost = cost;
+  use->cost_map[i].depends_on = depends_on;
+  use->cost_map[i].value = value;
 }
 
-/* Gets cost of (USE, CANDIDATE) pair.  Stores the bitmap of dependencies to
-   DEPENDS_ON.  */
+/* Gets cost of (USE, CANDIDATE) pair.  */
 
-static unsigned
-get_use_iv_cost (struct ivopts_data *data,
-                struct iv_use *use, struct iv_cand *cand, bitmap *depends_on)
+static struct cost_pair *
+get_use_iv_cost (struct ivopts_data *data, struct iv_use *use,
+                struct iv_cand *cand)
 {
-  unsigned i;
+  unsigned i, s;
+  struct cost_pair *ret;
 
   if (!cand)
-    return INFTY;
+    return NULL;
 
   if (data->consider_all_candidates)
-    i = cand->id;
-  else
     {
-      for (i = 0; i < use->n_map_members; i++)
-       if (use->cost_map[i].cand == cand)
-         break;
+      ret = use->cost_map + cand->id;
+      if (!ret->cand)
+       return NULL;
 
-      if (i == use->n_map_members)
-       return INFTY;
+      return ret;
     }
+      
+  /* n_map_members is a power of two, so this computes modulo.  */
+  s = cand->id & (use->n_map_members - 1);
+  for (i = s; i < use->n_map_members; i++)
+    if (use->cost_map[i].cand == cand)
+      return use->cost_map + i;
 
-  if (depends_on)
-    *depends_on = use->cost_map[i].depends_on;
-  return use->cost_map[i].cost;
+  for (i = 0; i < s; i++)
+    if (use->cost_map[i].cand == cand)
+      return use->cost_map + i;
+
+  return NULL;
 }
 
 /* Returns estimate on cost of computing SEQ.  */
@@ -1887,8 +2456,8 @@ static rtx
 produce_memory_decl_rtl (tree obj, int *regno)
 {
   rtx x;
-  if (!obj)
-    abort ();
+  
+  gcc_assert (obj);
   if (TREE_STATIC (obj) || DECL_EXTERNAL (obj))
     {
       const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (obj));
@@ -1914,10 +2483,9 @@ prepare_decl_rtl (tree *expr_p, int *ws, void *data)
     {
     case ADDR_EXPR:
       for (expr_p = &TREE_OPERAND (*expr_p, 0);
-          (handled_component_p (*expr_p)
-           || TREE_CODE (*expr_p) == REALPART_EXPR
-           || TREE_CODE (*expr_p) == IMAGPART_EXPR);
-          expr_p = &TREE_OPERAND (*expr_p, 0));
+          handled_component_p (*expr_p);
+          expr_p = &TREE_OPERAND (*expr_p, 0))
+       continue;
       obj = *expr_p;
       if (DECL_P (obj))
         x = produce_memory_decl_rtl (obj, regno);
@@ -1952,7 +2520,7 @@ prepare_decl_rtl (tree *expr_p, int *ws, void *data)
 
   if (x)
     {
-      VARRAY_PUSH_GENERIC_PTR_NOGC (decl_rtl_to_reset, obj);
+      VEC_safe_push (tree, heap, decl_rtl_to_reset, obj);
       SET_DECL_RTL (obj, x);
     }
 
@@ -1967,7 +2535,8 @@ computation_cost (tree expr)
   rtx seq, rslt;
   tree type = TREE_TYPE (expr);
   unsigned cost;
-  int regno = 0;
+  /* Avoid using hard regs in ways which may be unsupported.  */
+  int regno = LAST_VIRTUAL_REGISTER + 1;
 
   walk_tree (&expr, prepare_decl_rtl, &regno, NULL);
   start_sequence ();
@@ -1976,7 +2545,7 @@ computation_cost (tree expr)
   end_sequence ();
 
   cost = seq_cost (seq);
-  if (GET_CODE (rslt) == MEM)
+  if (MEM_P (rslt))
     cost += address_cost (XEXP (rslt, 0), TYPE_MODE (type));
 
   return cost;
@@ -1993,161 +2562,591 @@ var_at_stmt (struct loop *loop, struct iv_cand *cand, tree stmt)
     return cand->var_before;
 }
 
-/* Determines the expression by that USE is expressed from induction variable
-   CAND at statement AT in LOOP.  */
+/* Return the most significant (sign) bit of T.  Similar to tree_int_cst_msb,
+   but the bit is determined from TYPE_PRECISION, not MODE_BITSIZE.  */
 
-static tree
-get_computation_at (struct loop *loop,
-                   struct iv_use *use, struct iv_cand *cand, tree at)
+int
+tree_int_cst_sign_bit (tree t)
 {
-  tree ubase = unsave_expr_now (use->iv->base);
-  tree ustep = unsave_expr_now (use->iv->step);
-  tree cbase = unsave_expr_now (cand->iv->base);
-  tree cstep = unsave_expr_now (cand->iv->step);
-  tree utype = TREE_TYPE (ubase), ctype = TREE_TYPE (cbase);
-  tree uutype;
-  tree expr, delta;
-  tree ratio;
-  unsigned HOST_WIDE_INT ustepi, cstepi;
-  HOST_WIDE_INT ratioi;
+  unsigned bitno = TYPE_PRECISION (TREE_TYPE (t)) - 1;
+  unsigned HOST_WIDE_INT w;
 
-  if (TYPE_PRECISION (utype) > TYPE_PRECISION (ctype))
+  if (bitno < HOST_BITS_PER_WIDE_INT)
+    w = TREE_INT_CST_LOW (t);
+  else
     {
-      /* We do not have a precision to express the values of use.  */
-      return NULL_TREE;
+      w = TREE_INT_CST_HIGH (t);
+      bitno -= HOST_BITS_PER_WIDE_INT;
     }
 
-  expr = var_at_stmt (loop, cand, at);
+  return (w >> bitno) & 1;
+}
 
-  if (TREE_TYPE (expr) != ctype)
-    {
-      /* This may happen with the original ivs.  */
-      expr = fold_convert (ctype, expr);
-    }
+/* If we can prove that TOP = cst * BOT for some constant cst in TYPE,
+   return cst.  Otherwise return NULL_TREE.  */
 
-  if (TYPE_UNSIGNED (utype))
-    uutype = utype;
-  else
-    {
-      uutype = unsigned_type_for (utype);
-      ubase = fold_convert (uutype, ubase);
-      ustep = fold_convert (uutype, ustep);
-    }
+static tree
+constant_multiple_of (tree type, tree top, tree bot)
+{
+  tree res, mby, p0, p1;
+  enum tree_code code;
+  bool negate;
 
-  if (uutype != ctype)
+  STRIP_NOPS (top);
+  STRIP_NOPS (bot);
+
+  if (operand_equal_p (top, bot, 0))
+    return build_int_cst (type, 1);
+
+  code = TREE_CODE (top);
+  switch (code)
     {
-      expr = fold_convert (uutype, expr);
-      cbase = fold_convert (uutype, cbase);
-      cstep = fold_convert (uutype, cstep);
-    }
+    case MULT_EXPR:
+      mby = TREE_OPERAND (top, 1);
+      if (TREE_CODE (mby) != INTEGER_CST)
+       return NULL_TREE;
 
-  if (!cst_and_fits_in_hwi (cstep)
-      || !cst_and_fits_in_hwi (ustep))
-    return NULL_TREE;
+      res = constant_multiple_of (type, TREE_OPERAND (top, 0), bot);
+      if (!res)
+       return NULL_TREE;
 
-  ustepi = int_cst_value (ustep);
-  cstepi = int_cst_value (cstep);
+      return fold_binary_to_constant (MULT_EXPR, type, res,
+                                     fold_convert (type, mby));
 
-  if (!divide (TYPE_PRECISION (uutype), ustepi, cstepi, &ratioi))
-    {
-      /* TODO maybe consider case when ustep divides cstep and the ratio is
-        a power of 2 (so that the division is fast to execute)?  We would
-        need to be much more careful with overflows etc. then.  */
-      return NULL_TREE;
-    }
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      p0 = constant_multiple_of (type, TREE_OPERAND (top, 0), bot);
+      if (!p0)
+       return NULL_TREE;
+      p1 = constant_multiple_of (type, TREE_OPERAND (top, 1), bot);
+      if (!p1)
+       return NULL_TREE;
 
-  /* We may need to shift the value if we are after the increment.  */
-  if (stmt_after_increment (loop, cand, at))
-    cbase = fold (build2 (PLUS_EXPR, uutype, cbase, cstep));
+      return fold_binary_to_constant (code, type, p0, p1);
 
-  /* use = ubase + ratio * (var - cbase).  If either cbase is a constant
-     or |ratio| == 1, it is better to handle this like
-     
-     ubase - ratio * cbase + ratio * var.  */
+    case INTEGER_CST:
+      if (TREE_CODE (bot) != INTEGER_CST)
+       return NULL_TREE;
 
-  if (ratioi == 1)
-    {
-      delta = fold (build2 (MINUS_EXPR, uutype, ubase, cbase));
-      expr = fold (build2 (PLUS_EXPR, uutype, expr, delta));
-    }
-  else if (ratioi == -1)
-    {
-      delta = fold (build2 (PLUS_EXPR, uutype, ubase, cbase));
-      expr = fold (build2 (MINUS_EXPR, uutype, delta, expr));
-    }
-  else if (TREE_CODE (cbase) == INTEGER_CST)
+      bot = fold_convert (type, bot);
+      top = fold_convert (type, top);
+
+      /* If BOT seems to be negative, try dividing by -BOT instead, and negate
+        the result afterwards.  */
+      if (tree_int_cst_sign_bit (bot))
+       {
+         negate = true;
+         bot = fold_unary_to_constant (NEGATE_EXPR, type, bot);
+       }
+      else
+       negate = false;
+
+      /* Ditto for TOP.  */
+      if (tree_int_cst_sign_bit (top))
+       {
+         negate = !negate;
+         top = fold_unary_to_constant (NEGATE_EXPR, type, top);
+       }
+
+      if (!zero_p (fold_binary_to_constant (TRUNC_MOD_EXPR, type, top, bot)))
+       return NULL_TREE;
+
+      res = fold_binary_to_constant (EXACT_DIV_EXPR, type, top, bot);
+      if (negate)
+       res = fold_unary_to_constant (NEGATE_EXPR, type, res);
+      return res;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Sets COMB to CST.  */
+
+static void
+aff_combination_const (struct affine_tree_combination *comb, tree type,
+                      unsigned HOST_WIDE_INT cst)
+{
+  unsigned prec = TYPE_PRECISION (type);
+
+  comb->type = type;
+  comb->mask = (((unsigned HOST_WIDE_INT) 2 << (prec - 1)) - 1);
+
+  comb->n = 0;
+  comb->rest = NULL_TREE;
+  comb->offset = cst & comb->mask;
+}
+
+/* Sets COMB to single element ELT.  */
+
+static void
+aff_combination_elt (struct affine_tree_combination *comb, tree type, tree elt)
+{
+  unsigned prec = TYPE_PRECISION (type);
+
+  comb->type = type;
+  comb->mask = (((unsigned HOST_WIDE_INT) 2 << (prec - 1)) - 1);
+
+  comb->n = 1;
+  comb->elts[0] = elt;
+  comb->coefs[0] = 1;
+  comb->rest = NULL_TREE;
+  comb->offset = 0;
+}
+
+/* Scales COMB by SCALE.  */
+
+static void
+aff_combination_scale (struct affine_tree_combination *comb,
+                      unsigned HOST_WIDE_INT scale)
+{
+  unsigned i, j;
+
+  if (scale == 1)
+    return;
+
+  if (scale == 0)
     {
-      ratio = build_int_cst_type (uutype, ratioi);
-      delta = fold (build2 (MULT_EXPR, uutype, ratio, cbase));
-      delta = fold (build2 (MINUS_EXPR, uutype, ubase, delta));
-      expr = fold (build2 (MULT_EXPR, uutype, ratio, expr));
-      expr = fold (build2 (PLUS_EXPR, uutype, delta, expr));
+      aff_combination_const (comb, comb->type, 0);
+      return;
     }
-  else
+
+  comb->offset = (scale * comb->offset) & comb->mask;
+  for (i = 0, j = 0; i < comb->n; i++)
     {
-      expr = fold (build2 (MINUS_EXPR, uutype, expr, cbase));
-      ratio = build_int_cst_type (uutype, ratioi);
-      expr = fold (build2 (MULT_EXPR, uutype, ratio, expr));
-      expr = fold (build2 (PLUS_EXPR, uutype, ubase, expr));
+      comb->coefs[j] = (scale * comb->coefs[i]) & comb->mask;
+      comb->elts[j] = comb->elts[i];
+      if (comb->coefs[j] != 0)
+       j++;
     }
+  comb->n = j;
 
-  return fold_convert (utype, expr);
+  if (comb->rest)
+    {
+      if (comb->n < MAX_AFF_ELTS)
+       {
+         comb->coefs[comb->n] = scale;
+         comb->elts[comb->n] = comb->rest;
+         comb->rest = NULL_TREE;
+         comb->n++;
+       }
+      else
+       comb->rest = fold_build2 (MULT_EXPR, comb->type, comb->rest,
+                                 build_int_cst_type (comb->type, scale));
+    }
 }
 
-/* Determines the expression by that USE is expressed from induction variable
-   CAND in LOOP.  */
+/* Adds ELT * SCALE to COMB.  */
 
-static tree
-get_computation (struct loop *loop, struct iv_use *use, struct iv_cand *cand)
+static void
+aff_combination_add_elt (struct affine_tree_combination *comb, tree elt,
+                        unsigned HOST_WIDE_INT scale)
 {
-  return get_computation_at (loop, use, cand, use->stmt);
+  unsigned i;
+
+  if (scale == 0)
+    return;
+
+  for (i = 0; i < comb->n; i++)
+    if (operand_equal_p (comb->elts[i], elt, 0))
+      {
+       comb->coefs[i] = (comb->coefs[i] + scale) & comb->mask;
+       if (comb->coefs[i])
+         return;
+
+       comb->n--;
+       comb->coefs[i] = comb->coefs[comb->n];
+       comb->elts[i] = comb->elts[comb->n];
+
+       if (comb->rest)
+         {
+           gcc_assert (comb->n == MAX_AFF_ELTS - 1);
+           comb->coefs[comb->n] = 1;
+           comb->elts[comb->n] = comb->rest;
+           comb->rest = NULL_TREE;
+           comb->n++;
+         }
+       return;
+      }
+  if (comb->n < MAX_AFF_ELTS)
+    {
+      comb->coefs[comb->n] = scale;
+      comb->elts[comb->n] = elt;
+      comb->n++;
+      return;
+    }
+
+  if (scale == 1)
+    elt = fold_convert (comb->type, elt);
+  else
+    elt = fold_build2 (MULT_EXPR, comb->type,
+                      fold_convert (comb->type, elt),
+                      build_int_cst_type (comb->type, scale)); 
+
+  if (comb->rest)
+    comb->rest = fold_build2 (PLUS_EXPR, comb->type, comb->rest, elt);
+  else
+    comb->rest = elt;
 }
 
-/* Strips constant offsets from EXPR and adds them to OFFSET.  */
+/* Adds COMB2 to COMB1.  */
 
 static void
-strip_offset (tree *expr, unsigned HOST_WIDE_INT *offset)
+aff_combination_add (struct affine_tree_combination *comb1,
+                    struct affine_tree_combination *comb2)
 {
-  tree op0, op1;
+  unsigned i;
+
+  comb1->offset = (comb1->offset + comb2->offset) & comb1->mask;
+  for (i = 0; i < comb2->n; i++)
+    aff_combination_add_elt (comb1, comb2->elts[i], comb2->coefs[i]);
+  if (comb2->rest)
+    aff_combination_add_elt (comb1, comb2->rest, 1);
+}
+
+/* Splits EXPR into an affine combination of parts.  */
+
+static void
+tree_to_aff_combination (tree expr, tree type,
+                        struct affine_tree_combination *comb)
+{
+  struct affine_tree_combination tmp;
   enum tree_code code;
-  
-  while (1)
+  tree cst, core, toffset;
+  HOST_WIDE_INT bitpos, bitsize;
+  enum machine_mode mode;
+  int unsignedp, volatilep;
+
+  STRIP_NOPS (expr);
+
+  code = TREE_CODE (expr);
+  switch (code)
     {
-      if (cst_and_fits_in_hwi (*expr))
+    case INTEGER_CST:
+      aff_combination_const (comb, type, int_cst_value (expr));
+      return;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      tree_to_aff_combination (TREE_OPERAND (expr, 0), type, comb);
+      tree_to_aff_combination (TREE_OPERAND (expr, 1), type, &tmp);
+      if (code == MINUS_EXPR)
+       aff_combination_scale (&tmp, -1);
+      aff_combination_add (comb, &tmp);
+      return;
+
+    case MULT_EXPR:
+      cst = TREE_OPERAND (expr, 1);
+      if (TREE_CODE (cst) != INTEGER_CST)
+       break;
+      tree_to_aff_combination (TREE_OPERAND (expr, 0), type, comb);
+      aff_combination_scale (comb, int_cst_value (cst));
+      return;
+
+    case NEGATE_EXPR:
+      tree_to_aff_combination (TREE_OPERAND (expr, 0), type, comb);
+      aff_combination_scale (comb, -1);
+      return;
+
+    case ADDR_EXPR:
+      core = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, &bitpos,
+                                 &toffset, &mode, &unsignedp, &volatilep,
+                                 false);
+      if (bitpos % BITS_PER_UNIT != 0)
+       break;
+      aff_combination_const (comb, type, bitpos / BITS_PER_UNIT);
+      core = build_fold_addr_expr (core);
+      if (TREE_CODE (core) == ADDR_EXPR)
+       aff_combination_add_elt (comb, core, 1);
+      else
        {
-         *offset += int_cst_value (*expr);
-         *expr = integer_zero_node;
-         return;
+         tree_to_aff_combination (core, type, &tmp);
+         aff_combination_add (comb, &tmp);
        }
+      if (toffset)
+       {
+         tree_to_aff_combination (toffset, type, &tmp);
+         aff_combination_add (comb, &tmp);
+       }
+      return;
 
-      code = TREE_CODE (*expr);
-     
-      if (code != PLUS_EXPR && code != MINUS_EXPR)
-       return;
+    default:
+      break;
+    }
 
-      op0 = TREE_OPERAND (*expr, 0);
-      op1 = TREE_OPERAND (*expr, 1);
+  aff_combination_elt (comb, type, expr);
+}
 
-      if (cst_and_fits_in_hwi (op1))
-       {
-         if (code == PLUS_EXPR)
-           *offset += int_cst_value (op1);
-         else
-           *offset -= int_cst_value (op1);
+/* Creates EXPR + ELT * SCALE in TYPE.  MASK is the mask for width of TYPE.  */
 
-         *expr = op0;
-         continue;
+static tree
+add_elt_to_tree (tree expr, tree type, tree elt, unsigned HOST_WIDE_INT scale,
+                unsigned HOST_WIDE_INT mask)
+{
+  enum tree_code code;
+
+  scale &= mask;
+  elt = fold_convert (type, elt);
+
+  if (scale == 1)
+    {
+      if (!expr)
+       return elt;
+
+      return fold_build2 (PLUS_EXPR, type, expr, elt);
+    }
+
+  if (scale == mask)
+    {
+      if (!expr)
+       return fold_build1 (NEGATE_EXPR, type, elt);
+
+      return fold_build2 (MINUS_EXPR, type, expr, elt);
+    }
+
+  if (!expr)
+    return fold_build2 (MULT_EXPR, type, elt,
+                       build_int_cst_type (type, scale));
+
+  if ((scale | (mask >> 1)) == mask)
+    {
+      /* Scale is negative.  */
+      code = MINUS_EXPR;
+      scale = (-scale) & mask;
+    }
+  else
+    code = PLUS_EXPR;
+
+  elt = fold_build2 (MULT_EXPR, type, elt,
+                    build_int_cst_type (type, scale));
+  return fold_build2 (code, type, expr, elt);
+}
+
+/* Copies the tree elements of COMB to ensure that they are not shared.  */
+
+static void
+unshare_aff_combination (struct affine_tree_combination *comb)
+{
+  unsigned i;
+
+  for (i = 0; i < comb->n; i++)
+    comb->elts[i] = unshare_expr (comb->elts[i]);
+  if (comb->rest)
+    comb->rest = unshare_expr (comb->rest);
+}
+
+/* Makes tree from the affine combination COMB.  */
+
+static tree
+aff_combination_to_tree (struct affine_tree_combination *comb)
+{
+  tree type = comb->type;
+  tree expr = comb->rest;
+  unsigned i;
+  unsigned HOST_WIDE_INT off, sgn;
+
+  /* Handle the special case produced by get_computation_aff when
+     the type does not fit in HOST_WIDE_INT.  */
+  if (comb->n == 0 && comb->offset == 0)
+    return fold_convert (type, expr);
+
+  gcc_assert (comb->n == MAX_AFF_ELTS || comb->rest == NULL_TREE);
+
+  for (i = 0; i < comb->n; i++)
+    expr = add_elt_to_tree (expr, type, comb->elts[i], comb->coefs[i],
+                           comb->mask);
+
+  if ((comb->offset | (comb->mask >> 1)) == comb->mask)
+    {
+      /* Offset is negative.  */
+      off = (-comb->offset) & comb->mask;
+      sgn = comb->mask;
+    }
+  else
+    {
+      off = comb->offset;
+      sgn = 1;
+    }
+  return add_elt_to_tree (expr, type, build_int_cst_type (type, off), sgn,
+                         comb->mask);
+}
+
+/* Determines the expression by that USE is expressed from induction variable
+   CAND at statement AT in LOOP.  The expression is stored in a decomposed
+   form into AFF.  Returns false if USE cannot be expressed using CAND.  */
+
+static bool
+get_computation_aff (struct loop *loop,
+                    struct iv_use *use, struct iv_cand *cand, tree at,
+                    struct affine_tree_combination *aff)
+{
+  tree ubase = use->iv->base;
+  tree ustep = use->iv->step;
+  tree cbase = cand->iv->base;
+  tree cstep = cand->iv->step;
+  tree utype = TREE_TYPE (ubase), ctype = TREE_TYPE (cbase);
+  tree uutype;
+  tree expr, delta;
+  tree ratio;
+  unsigned HOST_WIDE_INT ustepi, cstepi;
+  HOST_WIDE_INT ratioi;
+  struct affine_tree_combination cbase_aff, expr_aff;
+  tree cstep_orig = cstep, ustep_orig = ustep;
+
+  if (TYPE_PRECISION (utype) > TYPE_PRECISION (ctype))
+    {
+      /* We do not have a precision to express the values of use.  */
+      return false;
+    }
+
+  expr = var_at_stmt (loop, cand, at);
+
+  if (TREE_TYPE (expr) != ctype)
+    {
+      /* This may happen with the original ivs.  */
+      expr = fold_convert (ctype, expr);
+    }
+
+  if (TYPE_UNSIGNED (utype))
+    uutype = utype;
+  else
+    {
+      uutype = unsigned_type_for (utype);
+      ubase = fold_convert (uutype, ubase);
+      ustep = fold_convert (uutype, ustep);
+    }
+
+  if (uutype != ctype)
+    {
+      expr = fold_convert (uutype, expr);
+      cbase = fold_convert (uutype, cbase);
+      cstep = fold_convert (uutype, cstep);
+
+      /* If the conversion is not noop, we must take it into account when
+        considering the value of the step.  */
+      if (TYPE_PRECISION (utype) < TYPE_PRECISION (ctype))
+       cstep_orig = cstep;
+    }
+
+  if (cst_and_fits_in_hwi (cstep_orig)
+      && cst_and_fits_in_hwi (ustep_orig))
+    {
+      ustepi = int_cst_value (ustep_orig);
+      cstepi = int_cst_value (cstep_orig);
+
+      if (!divide (TYPE_PRECISION (uutype), ustepi, cstepi, &ratioi))
+       {
+         /* TODO maybe consider case when ustep divides cstep and the ratio is
+            a power of 2 (so that the division is fast to execute)?  We would
+            need to be much more careful with overflows etc. then.  */
+         return false;
        }
 
-      if (code != PLUS_EXPR)
-       return;
+      ratio = build_int_cst_type (uutype, ratioi);
+    }
+  else
+    {
+      ratio = constant_multiple_of (uutype, ustep_orig, cstep_orig);
+      if (!ratio)
+       return false;
 
-      if (!cst_and_fits_in_hwi (op0))
-       return;
+      /* Ratioi is only used to detect special cases when the multiplicative
+        factor is 1 or -1, so if we cannot convert ratio to HOST_WIDE_INT,
+        we may set it to 0.  We prefer cst_and_fits_in_hwi/int_cst_value
+        to integer_onep/integer_all_onesp, since the former ignores
+        TREE_OVERFLOW.  */
+      if (cst_and_fits_in_hwi (ratio))
+       ratioi = int_cst_value (ratio);
+      else if (integer_onep (ratio))
+       ratioi = 1;
+      else if (integer_all_onesp (ratio))
+       ratioi = -1;
+      else
+       ratioi = 0;
+    }
+
+  /* We may need to shift the value if we are after the increment.  */
+  if (stmt_after_increment (loop, cand, at))
+    cbase = fold_build2 (PLUS_EXPR, uutype, cbase, cstep);
+
+  /* use = ubase - ratio * cbase + ratio * var.
 
-      *offset += int_cst_value (op0);
-      *expr = op1;
+     In general case ubase + ratio * (var - cbase) could be better (one less
+     multiplication), but often it is possible to eliminate redundant parts
+     of computations from (ubase - ratio * cbase) term, and if it does not
+     happen, fold is able to apply the distributive law to obtain this form
+     anyway.  */
+
+  if (TYPE_PRECISION (uutype) > HOST_BITS_PER_WIDE_INT)
+    {
+      /* Let's compute in trees and just return the result in AFF.  This case
+        should not be very common, and fold itself is not that bad either,
+        so making the aff. functions more complicated to handle this case
+        is not that urgent.  */
+      if (ratioi == 1)
+       {
+         delta = fold_build2 (MINUS_EXPR, uutype, ubase, cbase);
+         expr = fold_build2 (PLUS_EXPR, uutype, expr, delta);
+       }
+      else if (ratioi == -1)
+       {
+         delta = fold_build2 (PLUS_EXPR, uutype, ubase, cbase);
+         expr = fold_build2 (MINUS_EXPR, uutype, delta, expr);
+       }
+      else
+       {
+         delta = fold_build2 (MULT_EXPR, uutype, cbase, ratio);
+         delta = fold_build2 (MINUS_EXPR, uutype, ubase, delta);
+         expr = fold_build2 (MULT_EXPR, uutype, ratio, expr);
+         expr = fold_build2 (PLUS_EXPR, uutype, delta, expr);
+       }
+
+      aff->type = uutype;
+      aff->n = 0;
+      aff->offset = 0;
+      aff->mask = 0;
+      aff->rest = expr;
+      return true;
     }
+
+  /* If we got here, the types fits in HOST_WIDE_INT, thus it must be
+     possible to compute ratioi.  */
+  gcc_assert (ratioi);
+
+  tree_to_aff_combination (ubase, uutype, aff);
+  tree_to_aff_combination (cbase, uutype, &cbase_aff);
+  tree_to_aff_combination (expr, uutype, &expr_aff);
+  aff_combination_scale (&cbase_aff, -ratioi);
+  aff_combination_scale (&expr_aff, ratioi);
+  aff_combination_add (aff, &cbase_aff);
+  aff_combination_add (aff, &expr_aff);
+
+  return true;
+}
+
+/* Determines the expression by that USE is expressed from induction variable
+   CAND at statement AT in LOOP.  The computation is unshared.  */
+
+static tree
+get_computation_at (struct loop *loop,
+                   struct iv_use *use, struct iv_cand *cand, tree at)
+{
+  struct affine_tree_combination aff;
+  tree type = TREE_TYPE (use->iv->base);
+
+  if (!get_computation_aff (loop, use, cand, at, &aff))
+    return NULL_TREE;
+  unshare_aff_combination (&aff);
+  return fold_convert (type, aff_combination_to_tree (&aff));
+}
+
+/* Determines the expression by that USE is expressed from induction variable
+   CAND in LOOP.  The computation is unshared.  */
+
+static tree
+get_computation (struct loop *loop, struct iv_use *use, struct iv_cand *cand)
+{
+  return get_computation_at (loop, use, cand, use->stmt);
 }
 
 /* Returns cost of addition in MODE.  */
@@ -2164,8 +3163,8 @@ add_cost (enum machine_mode mode)
 
   start_sequence ();
   force_operand (gen_rtx_fmt_ee (PLUS, mode,
-                                gen_raw_REG (mode, FIRST_PSEUDO_REGISTER),
-                                gen_raw_REG (mode, FIRST_PSEUDO_REGISTER + 1)),
+                                gen_raw_REG (mode, LAST_VIRTUAL_REGISTER + 1),
+                                gen_raw_REG (mode, LAST_VIRTUAL_REGISTER + 2)),
                 NULL_RTX);
   seq = get_insns ();
   end_sequence ();
@@ -2214,7 +3213,7 @@ mbc_entry_eq (const void *entry1, const void *entry2)
 
 /* Returns cost of multiplication by constant CST in MODE.  */
 
-static unsigned
+unsigned
 multiply_by_cost (HOST_WIDE_INT cst, enum machine_mode mode)
 {
   static htab_t costs;
@@ -2231,13 +3230,13 @@ multiply_by_cost (HOST_WIDE_INT cst, enum machine_mode mode)
   if (*cached)
     return (*cached)->cost;
 
-  *cached = xmalloc (sizeof (struct mbc_entry));
+  *cached = XNEW (struct mbc_entry);
   (*cached)->mode = mode;
   (*cached)->cst = cst;
 
   start_sequence ();
-  expand_mult (mode, gen_raw_REG (mode, FIRST_PSEUDO_REGISTER), GEN_INT (cst),
-              NULL_RTX, 0);
+  expand_mult (mode, gen_raw_REG (mode, LAST_VIRTUAL_REGISTER + 1),
+              gen_int_mode (cst, mode), NULL_RTX, 0);
   seq = get_insns ();
   end_sequence ();
   
@@ -2252,6 +3251,47 @@ multiply_by_cost (HOST_WIDE_INT cst, enum machine_mode mode)
   return cost;
 }
 
+/* Returns true if multiplying by RATIO is allowed in address.  */
+
+bool
+multiplier_allowed_in_address_p (HOST_WIDE_INT ratio)
+{
+#define MAX_RATIO 128
+  static sbitmap valid_mult;
+  
+  if (!valid_mult)
+    {
+      rtx reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1);
+      rtx addr;
+      HOST_WIDE_INT i;
+
+      valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
+      sbitmap_zero (valid_mult);
+      addr = gen_rtx_fmt_ee (MULT, Pmode, reg1, NULL_RTX);
+      for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
+       {
+         XEXP (addr, 1) = gen_int_mode (i, Pmode);
+         if (memory_address_p (Pmode, addr))
+           SET_BIT (valid_mult, i + MAX_RATIO);
+       }
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "  allowed multipliers:");
+         for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
+           if (TEST_BIT (valid_mult, i + MAX_RATIO))
+             fprintf (dump_file, " %d", (int) i);
+         fprintf (dump_file, "\n");
+         fprintf (dump_file, "\n");
+       }
+    }
+
+  if (ratio > MAX_RATIO || ratio < -MAX_RATIO)
+    return false;
+
+  return TEST_BIT (valid_mult, ratio + MAX_RATIO);
+}
+
 /* Returns cost of address in shape symbol + var + OFFSET + RATIO * index.
    If SYMBOL_PRESENT is false, symbol is omitted.  If VAR_PRESENT is false,
    variable is omitted.  The created memory accesses MODE.
@@ -2262,8 +3302,7 @@ static unsigned
 get_address_cost (bool symbol_present, bool var_present,
                  unsigned HOST_WIDE_INT offset, HOST_WIDE_INT ratio)
 {
-#define MAX_RATIO 128
-  static sbitmap valid_mult;
+  static bool initialized = false;
   static HOST_WIDE_INT rat, off;
   static HOST_WIDE_INT min_offset, max_offset;
   static unsigned costs[2][2][2][2];
@@ -2275,16 +3314,17 @@ get_address_cost (bool symbol_present, bool var_present,
   unsigned HOST_WIDE_INT mask;
   unsigned bits;
 
-  if (!valid_mult)
+  if (!initialized)
     {
       HOST_WIDE_INT i;
+      initialized = true;
 
-      reg1 = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER);
+      reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1);
 
       addr = gen_rtx_fmt_ee (PLUS, Pmode, reg1, NULL_RTX);
       for (i = 1; i <= 1 << 20; i <<= 1)
        {
-         XEXP (addr, 1) = GEN_INT (i);
+         XEXP (addr, 1) = gen_int_mode (i, Pmode);
          if (!memory_address_p (Pmode, addr))
            break;
        }
@@ -2293,7 +3333,7 @@ get_address_cost (bool symbol_present, bool var_present,
 
       for (i = 1; i <= 1 << 20; i <<= 1)
        {
-         XEXP (addr, 1) = GEN_INT (-i);
+         XEXP (addr, 1) = gen_int_mode (-i, Pmode);
          if (!memory_address_p (Pmode, addr))
            break;
        }
@@ -2306,29 +3346,13 @@ get_address_cost (bool symbol_present, bool var_present,
          fprintf (dump_file, "  max offset %d\n", (int) max_offset);
        }
 
-      valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
-      sbitmap_zero (valid_mult);
       rat = 1;
-      addr = gen_rtx_fmt_ee (MULT, Pmode, reg1, NULL_RTX);
-      for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
-       {
-         XEXP (addr, 1) = GEN_INT (i);
-         if (memory_address_p (Pmode, addr))
-           {
-             SET_BIT (valid_mult, i + MAX_RATIO);
-             rat = i;
-           }
-       }
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "  allowed multipliers:");
-         for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
-           if (TEST_BIT (valid_mult, i + MAX_RATIO))
-             fprintf (dump_file, " %d", (int) i);
-         fprintf (dump_file, "\n");
-         fprintf (dump_file, "\n");
-       }
+      for (i = 2; i <= MAX_RATIO; i++)
+       if (multiplier_allowed_in_address_p (i))
+         {
+           rat = i;
+           break;
+         }
     }
 
   bits = GET_MODE_BITSIZE (Pmode);
@@ -2339,10 +3363,10 @@ get_address_cost (bool symbol_present, bool var_present,
   s_offset = offset;
 
   cost = 0;
-  offset_p = (min_offset <= s_offset && s_offset <= max_offset);
+  offset_p = (s_offset != 0
+             && min_offset <= s_offset && s_offset <= max_offset);
   ratio_p = (ratio != 1
-            && -MAX_RATIO <= ratio && ratio <= MAX_RATIO
-            && TEST_BIT (valid_mult, ratio + MAX_RATIO));
+            && multiplier_allowed_in_address_p (ratio));
 
   if (ratio != 1 && !ratio_p)
     cost += multiply_by_cost (ratio, Pmode);
@@ -2356,12 +3380,16 @@ get_address_cost (bool symbol_present, bool var_present,
   acost = costs[symbol_present][var_present][offset_p][ratio_p];
   if (!acost)
     {
+      int old_cse_not_expected;
       acost = 0;
       
-      addr = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER);
-      reg1 = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER + 1);
+      addr = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1);
+      reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2);
       if (ratio_p)
-       addr = gen_rtx_fmt_ee (MULT, Pmode, addr, GEN_INT (rat));
+       addr = gen_rtx_fmt_ee (MULT, Pmode, addr, gen_int_mode (rat, Pmode));
+
+      if (var_present)
+       addr = gen_rtx_fmt_ee (PLUS, Pmode, addr, reg1);
 
       if (symbol_present)
        {
@@ -2370,27 +3398,23 @@ get_address_cost (bool symbol_present, bool var_present,
            base = gen_rtx_fmt_e (CONST, Pmode,
                                  gen_rtx_fmt_ee (PLUS, Pmode,
                                                  base,
-                                                 GEN_INT (off)));
-         if (var_present)
-           base = gen_rtx_fmt_ee (PLUS, Pmode, reg1, base);
-       }
-
-      else if (var_present)
-       {
-         base = reg1;
-         if (offset_p)
-           base = gen_rtx_fmt_ee (PLUS, Pmode, base, GEN_INT (off));
+                                                 gen_int_mode (off, Pmode)));
        }
       else if (offset_p)
-       base = GEN_INT (off);
+       base = gen_int_mode (off, Pmode);
       else
        base = NULL_RTX;
     
       if (base)
-       addr = gen_rtx_fmt_ee (PLUS, Pmode, base, addr);
+       addr = gen_rtx_fmt_ee (PLUS, Pmode, addr, base);
   
       start_sequence ();
+      /* To avoid splitting addressing modes, pretend that no cse will
+        follow.  */
+      old_cse_not_expected = cse_not_expected;
+      cse_not_expected = true;
       addr = memory_address (Pmode, addr);
+      cse_not_expected = old_cse_not_expected;
       seq = get_insns ();
       end_sequence ();
   
@@ -2405,41 +3429,18 @@ get_address_cost (bool symbol_present, bool var_present,
   return cost + acost;
 }
 
-/* Records invariants in *EXPR_P.  Callback for walk_tree.  DATA contains
-   the bitmap to that we should store it.  */
-
-static struct ivopts_data *fd_ivopts_data;
-static tree
-find_depends (tree *expr_p, int *ws ATTRIBUTE_UNUSED, void *data)
-{
-  bitmap *depends_on = data;
-  struct version_info *info;
-
-  if (TREE_CODE (*expr_p) != SSA_NAME)
-    return NULL_TREE;
-  info = name_info (fd_ivopts_data, *expr_p);
-
-  if (!info->inv_id || info->has_nonlin_use)
-    return NULL_TREE;
-
-  if (!*depends_on)
-    *depends_on = BITMAP_XMALLOC ();
-  bitmap_set_bit (*depends_on, info->inv_id);
-
-  return NULL_TREE;
-}
-
-/* Estimates cost of forcing EXPR into variable.  DEPENDS_ON is a set of the
-   invariants the computation depends on.  */
+/* Estimates cost of forcing expression EXPR into a variable.  */
 
-static unsigned
-force_var_cost (struct ivopts_data *data,
-               tree expr, bitmap *depends_on)
+unsigned
+force_expr_to_var_cost (tree expr)
 {
   static bool costs_initialized = false;
   static unsigned integer_cost;
   static unsigned symbol_cost;
   static unsigned address_cost;
+  tree op0, op1;
+  unsigned cost0, cost1, cost;
+  enum machine_mode mode;
 
   if (!costs_initialized)
     {
@@ -2463,7 +3464,7 @@ force_var_cost (struct ivopts_data *data,
                                    build_int_cst_type (type, 2000))) + 1;
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
-         fprintf (dump_file, "force_var_cost:\n");
+         fprintf (dump_file, "force_expr_to_var_cost:\n");
          fprintf (dump_file, "  integer %d\n", (int) integer_cost);
          fprintf (dump_file, "  symbol %d\n", (int) symbol_cost);
          fprintf (dump_file, "  address %d\n", (int) address_cost);
@@ -2474,11 +3475,7 @@ force_var_cost (struct ivopts_data *data,
       costs_initialized = true;
     }
 
-  if (depends_on)
-    {
-      fd_ivopts_data = data;
-      walk_tree (&expr, find_depends, depends_on, NULL);
-    }
+  STRIP_NOPS (expr);
 
   if (SSA_VAR_P (expr))
     return 0;
@@ -2501,98 +3498,78 @@ force_var_cost (struct ivopts_data *data,
       return address_cost;
     }
 
-  /* Just an arbitrary value, FIXME.  */
-  return target_spill_cost;
-}
-
-/* Peels a single layer of ADDR.  If DIFF is not NULL, do it only if the
-   offset is constant and add the offset to DIFF.  */
-
-static tree
-peel_address (tree addr, unsigned HOST_WIDE_INT *diff)
-{
-  tree off, size;
-  HOST_WIDE_INT bit_offset;
-
-  switch (TREE_CODE (addr))
+  switch (TREE_CODE (expr))
     {
-    case SSA_NAME:
-    case INDIRECT_REF:
-    case BIT_FIELD_REF:
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case STRING_CST:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      return NULL_TREE;
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+      op0 = TREE_OPERAND (expr, 0);
+      op1 = TREE_OPERAND (expr, 1);
+      STRIP_NOPS (op0);
+      STRIP_NOPS (op1);
 
-    case COMPONENT_REF:
-      off = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (addr, 1));
-      bit_offset = TREE_INT_CST_LOW (off);
-
-      if (bit_offset % BITS_PER_UNIT)
-       abort ();
-      
-      if (diff)
-       *diff += bit_offset / BITS_PER_UNIT;
-
-      return TREE_OPERAND (addr, 0);
+      if (is_gimple_val (op0))
+       cost0 = 0;
+      else
+       cost0 = force_expr_to_var_cost (op0);
 
-    case ARRAY_REF:
-      off = TREE_OPERAND (addr, 1);
+      if (is_gimple_val (op1))
+       cost1 = 0;
+      else
+       cost1 = force_expr_to_var_cost (op1);
 
-      if (diff)
-       {
-         if (!cst_and_fits_in_hwi (off))
-           return NULL_TREE;
+      break;
 
-         size = TYPE_SIZE_UNIT (TREE_TYPE (addr));
-         if (!cst_and_fits_in_hwi (size))
-           return NULL_TREE;
+    default:
+      /* Just an arbitrary value, FIXME.  */
+      return target_spill_cost;
+    }
 
-         *diff += TREE_INT_CST_LOW (off) * TREE_INT_CST_LOW (size);
-       }
+  mode = TYPE_MODE (TREE_TYPE (expr));
+  switch (TREE_CODE (expr))
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      cost = add_cost (mode);
+      break;
 
-      return TREE_OPERAND (addr, 0);
+    case MULT_EXPR:
+      if (cst_and_fits_in_hwi (op0))
+       cost = multiply_by_cost (int_cst_value (op0), mode);
+      else if (cst_and_fits_in_hwi (op1))
+       cost = multiply_by_cost (int_cst_value (op1), mode);
+      else
+       return target_spill_cost;
+      break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
-}
 
-/* Checks whether E1 and E2 have constant difference, and if they do,
-   store it in *DIFF.  */
+  cost += cost0;
+  cost += cost1;
 
-static bool
-ptr_difference_const (tree e1, tree e2, unsigned HOST_WIDE_INT *diff)
-{
-  int d1 = 0, d2 = 0;
-  tree x;
-  unsigned HOST_WIDE_INT delta1 = 0, delta2 = 0;
-
-  /* Find depths of E1 and E2.  */
-  for (x = e1; x; x = peel_address (x, NULL))
-    d1++;
-  for (x = e2; x; x = peel_address (x, NULL))
-    d2++;
+  /* Bound the cost by target_spill_cost.  The parts of complicated
+     computations often are either loop invariant or at least can
+     be shared between several iv uses, so letting this grow without
+     limits would not give reasonable results.  */
+  return cost < target_spill_cost ? cost : target_spill_cost;
+}
 
-  for (; e1 && d1 > d2; e1 = peel_address (e1, &delta1))
-    d1--;
-  for (; e2 && d2 > d1; e2 = peel_address (e2, &delta2))
-    d2--;
+/* Estimates cost of forcing EXPR into a variable.  DEPENDS_ON is a set of the
+   invariants the computation depends on.  */
 
-  while (e1 && e2 && !operand_equal_p (e1, e2, 0))
+static unsigned
+force_var_cost (struct ivopts_data *data,
+               tree expr, bitmap *depends_on)
+{
+  if (depends_on)
     {
-      e1 = peel_address (e1, &delta1);
-      e2 = peel_address (e2, &delta1);
+      fd_ivopts_data = data;
+      walk_tree (&expr, find_depends, depends_on, NULL);
     }
 
-  if (!e1 || !e2)
-    return false;
-
-  *diff = delta1 - delta2;
-  return true;
+  return force_expr_to_var_cost (expr);
 }
 
 /* Estimates cost of expressing address ADDR  as var + symbol + offset.  The
@@ -2605,21 +3582,28 @@ split_address_cost (struct ivopts_data *data,
                    tree addr, bool *symbol_present, bool *var_present,
                    unsigned HOST_WIDE_INT *offset, bitmap *depends_on)
 {
-  tree core = addr;
-
-  while (core
-        && TREE_CODE (core) != VAR_DECL)
-    core = peel_address (core, offset);
+  tree core;
+  HOST_WIDE_INT bitsize;
+  HOST_WIDE_INT bitpos;
+  tree toffset;
+  enum machine_mode mode;
+  int unsignedp, volatilep;
+  
+  core = get_inner_reference (addr, &bitsize, &bitpos, &toffset, &mode,
+                             &unsignedp, &volatilep, false);
 
-  if (!core)
+  if (toffset != 0
+      || bitpos % BITS_PER_UNIT != 0
+      || TREE_CODE (core) != VAR_DECL)
     {
       *symbol_present = false;
       *var_present = true;
       fd_ivopts_data = data;
       walk_tree (&addr, find_depends, depends_on, NULL);
       return target_spill_cost;
-    }  
-         
+    }
+
+  *offset += bitpos / BITS_PER_UNIT;
   if (TREE_STATIC (core)
       || DECL_EXTERNAL (core))
     {
@@ -2644,15 +3628,12 @@ ptr_difference_cost (struct ivopts_data *data,
                     tree e1, tree e2, bool *symbol_present, bool *var_present,
                     unsigned HOST_WIDE_INT *offset, bitmap *depends_on)
 {
-  unsigned HOST_WIDE_INT diff = 0;
+  HOST_WIDE_INT diff = 0;
   unsigned cost;
 
-  if (TREE_CODE (e1) != ADDR_EXPR)
-    abort ();
+  gcc_assert (TREE_CODE (e1) == ADDR_EXPR);
 
-  if (TREE_CODE (e2) == ADDR_EXPR
-      && ptr_difference_const (TREE_OPERAND (e1, 0),
-                              TREE_OPERAND (e2, 0), &diff))
+  if (ptr_difference_const (e1, e2, &diff))
     {
       *offset += diff;
       *symbol_present = false;
@@ -2687,11 +3668,14 @@ difference_cost (struct ivopts_data *data,
 {
   unsigned cost;
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (e1));
+  unsigned HOST_WIDE_INT off1, off2;
 
-  strip_offset (&e1, offset);
-  *offset = -*offset;
-  strip_offset (&e2, offset);
-  *offset = -*offset;
+  e1 = strip_offset (e1, &off1);
+  e2 = strip_offset (e2, &off2);
+  *offset += off1 - off2;
+
+  STRIP_NOPS (e1);
+  STRIP_NOPS (e2);
 
   if (TREE_CODE (e1) == ADDR_EXPR)
     return ptr_difference_cost (data, e1, e2, symbol_present, var_present, offset,
@@ -2757,20 +3741,18 @@ get_computation_cost_at (struct ivopts_data *data,
       return INFTY;
     }
 
-  if (!cst_and_fits_in_hwi (ustep)
-      || !cst_and_fits_in_hwi (cstep))
-    return INFTY;
-
-  if (TREE_CODE (ubase) == INTEGER_CST
-      && !cst_and_fits_in_hwi (ubase))
-    goto fallback;
-
-  if (TREE_CODE (cbase) == INTEGER_CST
-      && !cst_and_fits_in_hwi (cbase))
-    goto fallback;
-    
-  ustepi = int_cst_value (ustep);
-  cstepi = int_cst_value (cstep);
+  if (address_p)
+    {
+      /* Do not try to express address of an object with computation based
+        on address of a different object.  This may cause problems in rtl
+        level alias analysis (that does not expect this to be happening,
+        as this is illegal in C), and would be unlikely to be useful
+        anyway.  */
+      if (use->iv->base_object
+         && cand->iv->base_object
+         && !operand_equal_p (use->iv->base_object, cand->iv->base_object, 0))
+       return INFTY;
+    }
 
   if (TYPE_PRECISION (utype) != TYPE_PRECISION (ctype))
     {
@@ -2778,8 +3760,43 @@ get_computation_cost_at (struct ivopts_data *data,
       goto fallback;
     }
 
-  if (!divide (TYPE_PRECISION (utype), ustepi, cstepi, &ratio))
-    return INFTY;
+  /* CSTEPI is removed from the offset in case statement is after the
+     increment.  If the step is not constant, we use zero instead.
+     This is a bit imprecise (there is the extra addition), but
+     redundancy elimination is likely to transform the code so that
+     it uses value of the variable before increment anyway,
+     so it is not that much unrealistic.  */
+  if (cst_and_fits_in_hwi (cstep))
+    cstepi = int_cst_value (cstep);
+  else
+    cstepi = 0;
+
+  if (cst_and_fits_in_hwi (ustep)
+      && cst_and_fits_in_hwi (cstep))
+    {
+      ustepi = int_cst_value (ustep);
+
+      if (!divide (TYPE_PRECISION (utype), ustepi, cstepi, &ratio))
+       return INFTY;
+    }
+  else
+    {
+      tree rat;
+      
+      rat = constant_multiple_of (utype, ustep, cstep);
+    
+      if (!rat)
+       return INFTY;
+
+      if (cst_and_fits_in_hwi (rat))
+       ratio = int_cst_value (rat);
+      else if (integer_onep (rat))
+       ratio = 1;
+      else if (integer_all_onesp (rat))
+       ratio = -1;
+      else
+       return INFTY;
+    }
 
   /* use = ubase + ratio * (var - cbase).  If either cbase is a constant
      or ratio == 1, it is better to handle this like
@@ -2788,7 +3805,7 @@ get_computation_cost_at (struct ivopts_data *data,
      
      (also holds in the case ratio == -1, TODO.  */
 
-  if (TREE_CODE (cbase) == INTEGER_CST)
+  if (cst_and_fits_in_hwi (cbase))
     {
       offset = - ratio * int_cst_value (cbase); 
       cost += difference_cost (data,
@@ -2822,7 +3839,7 @@ get_computation_cost_at (struct ivopts_data *data,
      (symbol/var/const parts may be omitted).  If we are looking for an address,
      find the cost of addressing this.  */
   if (address_p)
-    return get_address_cost (symbol_present, var_present, offset, ratio);
+    return cost + get_address_cost (symbol_present, var_present, offset, ratio);
 
   /* Otherwise estimate the costs for computing the expression.  */
   aratio = ratio > 0 ? ratio : -ratio;
@@ -2878,26 +3895,42 @@ get_computation_cost (struct ivopts_data *data,
 /* Determines cost of basing replacement of USE on CAND in a generic
    expression.  */
 
-static void
+static bool
 determine_use_iv_cost_generic (struct ivopts_data *data,
                               struct iv_use *use, struct iv_cand *cand)
 {
   bitmap depends_on;
-  unsigned cost = get_computation_cost (data, use, cand, false, &depends_on);
+  unsigned cost;
+
+  /* The simple case first -- if we need to express value of the preserved
+     original biv, the cost is 0.  This also prevents us from counting the
+     cost of increment twice -- once at this use and once in the cost of
+     the candidate.  */
+  if (cand->pos == IP_ORIGINAL
+      && cand->incremented_at == use->stmt)
+    {
+      set_use_iv_cost (data, use, cand, 0, NULL, NULL_TREE);
+      return true;
+    }
 
-  set_use_iv_cost (data, use, cand, cost, depends_on);
+  cost = get_computation_cost (data, use, cand, false, &depends_on);
+  set_use_iv_cost (data, use, cand, cost, depends_on, NULL_TREE);
+
+  return cost != INFTY;
 }
 
 /* Determines cost of basing replacement of USE on CAND in an address.  */
 
-static void
+static bool
 determine_use_iv_cost_address (struct ivopts_data *data,
                               struct iv_use *use, struct iv_cand *cand)
 {
   bitmap depends_on;
   unsigned cost = get_computation_cost (data, use, cand, true, &depends_on);
 
-  set_use_iv_cost (data, use, cand, cost, depends_on);
+  set_use_iv_cost (data, use, cand, cost, depends_on, NULL_TREE);
+
+  return cost != INFTY;
 }
 
 /* Computes value of induction variable IV in iteration NITER.  */
@@ -2909,9 +3942,9 @@ iv_value (struct iv *iv, tree niter)
   tree type = TREE_TYPE (iv->base);
 
   niter = fold_convert (type, niter);
-  val = fold (build2 (MULT_EXPR, type, iv->step, unsave_expr_now (niter)));
+  val = fold_build2 (MULT_EXPR, type, iv->step, niter);
 
-  return fold (build2 (PLUS_EXPR, type, iv->base, val));
+  return fold_build2 (PLUS_EXPR, type, iv->base, val);
 }
 
 /* Computes value of candidate CAND at position AT in iteration NITER.  */
@@ -2923,117 +3956,170 @@ cand_value_at (struct loop *loop, struct iv_cand *cand, tree at, tree niter)
   tree type = TREE_TYPE (cand->iv->base);
 
   if (stmt_after_increment (loop, cand, at))
-    val = fold (build2 (PLUS_EXPR, type, val, cand->iv->step));
+    val = fold_build2 (PLUS_EXPR, type, val, cand->iv->step);
 
   return val;
 }
 
+/* Returns period of induction variable iv.  */
+
+static tree
+iv_period (struct iv *iv)
+{
+  tree step = iv->step, period, type;
+  tree pow2div;
+
+  gcc_assert (step && TREE_CODE (step) == INTEGER_CST);
+
+  /* Period of the iv is gcd (step, type range).  Since type range is power
+     of two, it suffices to determine the maximum power of two that divides
+     step.  */
+  pow2div = num_ending_zeros (step);
+  type = unsigned_type_for (TREE_TYPE (step));
+
+  period = build_low_bits_mask (type,
+                               (TYPE_PRECISION (type)
+                                - tree_low_cst (pow2div, 1)));
+
+  return period;
+}
+
+/* Returns the comparison operator used when eliminating the iv USE.  */
+
+static enum tree_code
+iv_elimination_compare (struct ivopts_data *data, struct iv_use *use)
+{
+  struct loop *loop = data->current_loop;
+  basic_block ex_bb;
+  edge exit;
+
+  ex_bb = bb_for_stmt (use->stmt);
+  exit = EDGE_SUCC (ex_bb, 0);
+  if (flow_bb_inside_loop_p (loop, exit->dest))
+    exit = EDGE_SUCC (ex_bb, 1);
+
+  return (exit->flags & EDGE_TRUE_VALUE ? EQ_EXPR : NE_EXPR);
+}
+
 /* Check whether it is possible to express the condition in USE by comparison
-   of candidate CAND.  If so, store the comparison code to COMPARE and the
-   value compared with to BOUND.  */
+   of candidate CAND.  If so, store the value compared with to BOUND.  */
 
 static bool
-may_eliminate_iv (struct loop *loop,
-                 struct iv_use *use, struct iv_cand *cand,
-                 enum tree_code *compare, tree *bound)
+may_eliminate_iv (struct ivopts_data *data,
+                 struct iv_use *use, struct iv_cand *cand, tree *bound)
 {
+  basic_block ex_bb;
   edge exit;
-  struct tree_niter_desc *niter, new_niter;
-  tree wider_type, type, base;
+  struct tree_niter_desc *niter;
+  tree nit, nit_type;
+  tree wider_type, period, per_type;
+  struct loop *loop = data->current_loop;
+  
+  if (TREE_CODE (cand->iv->step) != INTEGER_CST)
+    return false;
 
-  /* For now just very primitive -- we work just for the single exit condition,
-     and are quite conservative about the possible overflows.  TODO -- both of
-     these can be improved.  */
-  exit = single_dom_exit (loop);
-  if (!exit)
+  /* For now works only for exits that dominate the loop latch.  TODO -- extend
+     for other conditions inside loop body.  */
+  ex_bb = bb_for_stmt (use->stmt);
+  if (use->stmt != last_stmt (ex_bb)
+      || TREE_CODE (use->stmt) != COND_EXPR)
     return false;
-  if (use->stmt != last_stmt (exit->src))
+  if (!dominated_by_p (CDI_DOMINATORS, loop->latch, ex_bb))
     return false;
 
-  niter = &loop_data (loop)->niter;
-  if (!niter->niter
-      || !integer_nonzerop (niter->assumptions)
-      || !integer_zerop (niter->may_be_zero))
+  exit = EDGE_SUCC (ex_bb, 0);
+  if (flow_bb_inside_loop_p (loop, exit->dest))
+    exit = EDGE_SUCC (ex_bb, 1);
+  if (flow_bb_inside_loop_p (loop, exit->dest))
     return false;
 
-  if (exit->flags & EDGE_TRUE_VALUE)
-    *compare = EQ_EXPR;
-  else
-    *compare = NE_EXPR;
+  niter = niter_for_exit (data, exit);
+  if (!niter
+      || !zero_p (niter->may_be_zero))
+    return false;
 
-  *bound = cand_value_at (loop, cand, use->stmt, niter->niter);
+  nit = niter->niter;
+  nit_type = TREE_TYPE (nit);
 
-  /* Let us check there is not some problem with overflows, by checking that
-     the number of iterations is unchanged.  */
-  base = cand->iv->base;
-  type = TREE_TYPE (base);
-  if (stmt_after_increment (loop, cand, use->stmt))
-    base = fold (build2 (PLUS_EXPR, type, base, cand->iv->step));
-
-  new_niter.niter = NULL_TREE;
-  number_of_iterations_cond (TREE_TYPE (cand->iv->base), base,
-                            cand->iv->step, NE_EXPR, *bound, NULL_TREE,
-                            &new_niter);
-  if (!new_niter.niter
-      || !integer_nonzerop (new_niter.assumptions)
-      || !integer_zerop (new_niter.may_be_zero))
+  /* Determine whether we may use the variable to test whether niter iterations
+     elapsed.  This is the case iff the period of the induction variable is
+     greater than the number of iterations.  */
+  period = iv_period (cand->iv);
+  if (!period)
     return false;
+  per_type = TREE_TYPE (period);
+
+  wider_type = TREE_TYPE (period);
+  if (TYPE_PRECISION (nit_type) < TYPE_PRECISION (per_type))
+    wider_type = per_type;
+  else
+    wider_type = nit_type;
 
-  wider_type = TREE_TYPE (new_niter.niter);
-  if (TYPE_PRECISION (wider_type) < TYPE_PRECISION (TREE_TYPE (niter->niter)))
-    wider_type = TREE_TYPE (niter->niter);
-  if (!operand_equal_p (fold_convert (wider_type, niter->niter),
-                       fold_convert (wider_type, new_niter.niter), 0))
+  if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
+                                     fold_convert (wider_type, period),
+                                     fold_convert (wider_type, nit))))
     return false;
 
+  *bound = cand_value_at (loop, cand, use->stmt, nit);
   return true;
 }
 
 /* Determines cost of basing replacement of USE on CAND in a condition.  */
 
-static void
+static bool
 determine_use_iv_cost_condition (struct ivopts_data *data,
                                 struct iv_use *use, struct iv_cand *cand)
 {
-  tree bound;
-  enum tree_code compare;
+  tree bound = NULL_TREE, op, cond;
+  bitmap depends_on = NULL;
+  unsigned cost;
 
   /* Only consider real candidates.  */
   if (!cand->iv)
     {
-      set_use_iv_cost (data, use, cand, INFTY, NULL);
-      return;
+      set_use_iv_cost (data, use, cand, INFTY, NULL, NULL_TREE);
+      return false;
     }
 
-  if (may_eliminate_iv (data->current_loop, use, cand, &compare, &bound))
+  if (may_eliminate_iv (data, use, cand, &bound))
     {
-      bitmap depends_on = NULL;
-      unsigned cost = force_var_cost (data, bound, &depends_on);
+      cost = force_var_cost (data, bound, &depends_on);
 
-      set_use_iv_cost (data, use, cand, cost, depends_on);
-      return;
+      set_use_iv_cost (data, use, cand, cost, depends_on, bound);
+      return cost != INFTY;
     }
 
   /* The induction variable elimination failed; just express the original
      giv.  If it is compared with an invariant, note that we cannot get
      rid of it.  */
-  if (TREE_CODE (*use->op_p) == SSA_NAME)
-    record_invariant (data, *use->op_p, true);
-  else
+  cost = get_computation_cost (data, use, cand, false, &depends_on);
+
+  cond = *use->op_p;
+  if (TREE_CODE (cond) != SSA_NAME)
     {
-      record_invariant (data, TREE_OPERAND (*use->op_p, 0), true);
-      record_invariant (data, TREE_OPERAND (*use->op_p, 1), true);
+      op = TREE_OPERAND (cond, 0);
+      if (TREE_CODE (op) == SSA_NAME && !zero_p (get_iv (data, op)->step))
+       op = TREE_OPERAND (cond, 1);
+      if (TREE_CODE (op) == SSA_NAME)
+       {
+         op = get_iv (data, op)->base;
+         fd_ivopts_data = data;
+         walk_tree (&op, find_depends, &depends_on, NULL);
+       }
     }
 
-  determine_use_iv_cost_generic (data, use, cand);
+  set_use_iv_cost (data, use, cand, cost, depends_on, NULL);
+  return cost != INFTY;
 }
 
 /* Checks whether it is possible to replace the final value of USE by
    a direct computation.  If so, the formula is stored to *VALUE.  */
 
 static bool
-may_replace_final_value (struct loop *loop, struct iv_use *use, tree *value)
+may_replace_final_value (struct ivopts_data *data, struct iv_use *use,
+                        tree *value)
 {
+  struct loop *loop = data->current_loop;
   edge exit;
   struct tree_niter_desc *niter;
 
@@ -3041,14 +4127,12 @@ may_replace_final_value (struct loop *loop, struct iv_use *use, tree *value)
   if (!exit)
     return false;
 
-  if (!dominated_by_p (CDI_DOMINATORS, exit->src,
-                      bb_for_stmt (use->stmt)))
-    abort ();
+  gcc_assert (dominated_by_p (CDI_DOMINATORS, exit->src,
+                             bb_for_stmt (use->stmt)));
 
-  niter = &loop_data (loop)->niter;
-  if (!niter->niter
-      || !operand_equal_p (niter->assumptions, boolean_true_node, 0)
-      || !operand_equal_p (niter->may_be_zero, boolean_false_node, 0))
+  niter = niter_for_single_dom_exit (data);
+  if (!niter
+      || !zero_p (niter->may_be_zero))
     return false;
 
   *value = iv_value (use->iv, niter->niter);
@@ -3058,22 +4142,33 @@ may_replace_final_value (struct loop *loop, struct iv_use *use, tree *value)
 
 /* Determines cost of replacing final value of USE using CAND.  */
 
-static void
+static bool
 determine_use_iv_cost_outer (struct ivopts_data *data,
                             struct iv_use *use, struct iv_cand *cand)
 {
   bitmap depends_on;
   unsigned cost;
   edge exit;
-  tree value;
+  tree value = NULL_TREE;
   struct loop *loop = data->current_loop;
-         
+
+  /* The simple case first -- if we need to express value of the preserved
+     original biv, the cost is 0.  This also prevents us from counting the
+     cost of increment twice -- once at this use and once in the cost of
+     the candidate.  */
+  if (cand->pos == IP_ORIGINAL
+      && cand->incremented_at == use->stmt)
+    {
+      set_use_iv_cost (data, use, cand, 0, NULL, NULL_TREE);
+      return true;
+    }
+
   if (!cand->iv)
     {
-      if (!may_replace_final_value (loop, use, &value))
+      if (!may_replace_final_value (data, use, &value))
        {
-         set_use_iv_cost (data, use, cand, INFTY, NULL);
-         return;
+         set_use_iv_cost (data, use, cand, INFTY, NULL, NULL_TREE);
+         return false;
        }
 
       depends_on = NULL;
@@ -3081,8 +4176,8 @@ determine_use_iv_cost_outer (struct ivopts_data *data,
 
       cost /= AVG_LOOP_NITER (loop);
 
-      set_use_iv_cost (data, use, cand, cost, depends_on);
-      return;
+      set_use_iv_cost (data, use, cand, cost, depends_on, value);
+      return cost != INFTY;
     }
 
   exit = single_dom_exit (loop);
@@ -3101,35 +4196,34 @@ determine_use_iv_cost_outer (struct ivopts_data *data,
       cost = get_computation_cost (data, use, cand, false, &depends_on);
     }
                                   
-  set_use_iv_cost (data, use, cand, cost, depends_on);
+  set_use_iv_cost (data, use, cand, cost, depends_on, NULL_TREE);
+
+  return cost != INFTY;
 }
 
-/* Determines cost of basing replacement of USE on CAND.  */
+/* Determines cost of basing replacement of USE on CAND.  Returns false
+   if USE cannot be based on CAND.  */
 
-static void
+static bool
 determine_use_iv_cost (struct ivopts_data *data,
                       struct iv_use *use, struct iv_cand *cand)
 {
   switch (use->type)
     {
     case USE_NONLINEAR_EXPR:
-      determine_use_iv_cost_generic (data, use, cand);
-      break;
+      return determine_use_iv_cost_generic (data, use, cand);
 
     case USE_OUTER:
-      determine_use_iv_cost_outer (data, use, cand);
-      break;
+      return determine_use_iv_cost_outer (data, use, cand);
 
     case USE_ADDRESS:
-      determine_use_iv_cost_address (data, use, cand);
-      break;
+      return determine_use_iv_cost_address (data, use, cand);
 
     case USE_COMPARE:
-      determine_use_iv_cost_condition (data, use, cand);
-      break;
+      return determine_use_iv_cost_condition (data, use, cand);
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -3141,28 +4235,10 @@ determine_use_iv_costs (struct ivopts_data *data)
   unsigned i, j;
   struct iv_use *use;
   struct iv_cand *cand;
-
-  data->consider_all_candidates = (n_iv_cands (data)
-                                  <= CONSIDER_ALL_CANDIDATES_BOUND);
+  bitmap to_clear = BITMAP_ALLOC (NULL);
 
   alloc_use_cost_map (data);
 
-  if (!data->consider_all_candidates)
-    {
-      /* Add the important candidate entries.  */
-      for (j = 0; j < n_iv_cands (data); j++)
-       {
-         cand = iv_cand (data, j);
-         if (!cand->important)
-           continue;
-         for (i = 0; i < n_iv_uses (data); i++)
-           {
-             use = iv_use (data, i);
-             determine_use_iv_cost (data, use, cand);
-           }
-       }
-    }
-
   for (i = 0; i < n_iv_uses (data); i++)
     {
       use = iv_use (data, i);
@@ -3177,15 +4253,24 @@ determine_use_iv_costs (struct ivopts_data *data)
        }
       else
        {
-         EXECUTE_IF_SET_IN_BITMAP (use->related_cands, 0, j,
+         bitmap_iterator bi;
+
+         EXECUTE_IF_SET_IN_BITMAP (use->related_cands, 0, j, bi)
            {
              cand = iv_cand (data, j);
-             if (!cand->important)
-               determine_use_iv_cost (data, use, cand);
-           });
+             if (!determine_use_iv_cost (data, use, cand))
+               bitmap_set_bit (to_clear, j);
+           }
+
+         /* Remove the candidates for that the cost is infinite from
+            the list of related candidates.  */
+         bitmap_and_compl_into (use->related_cands, to_clear);
+         bitmap_clear (to_clear);
        }
     }
 
+  BITMAP_FREE (to_clear);
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Use-candidate costs:\n");
@@ -3223,8 +4308,7 @@ static void
 determine_iv_cost (struct ivopts_data *data, struct iv_cand *cand)
 {
   unsigned cost_base, cost_step;
-  tree base, last;
-  basic_block bb;
+  tree base;
 
   if (!cand->iv)
     {
@@ -3242,21 +4326,18 @@ determine_iv_cost (struct ivopts_data *data, struct iv_cand *cand)
 
   cand->cost = cost_step + cost_base / AVG_LOOP_NITER (current_loop);
 
-  /* Prefer the original iv unless we may gain something by replacing it.  */
-  if (cand->pos == IP_ORIGINAL)
+  /* Prefer the original iv unless we may gain something by replacing it;
+     this is not really relevant for artificial ivs created by other
+     passes.  */
+  if (cand->pos == IP_ORIGINAL
+      && !DECL_ARTIFICIAL (SSA_NAME_VAR (cand->var_before)))
     cand->cost--;
   
   /* Prefer not to insert statements into latch unless there are some
      already (so that we do not create unnecessary jumps).  */
-  if (cand->pos == IP_END)
-    {
-      bb = ip_end_pos (data->current_loop);
-      last = last_stmt (bb);
-
-      if (!last
-         || TREE_CODE (last) == LABEL_EXPR)
-       cand->cost++;
-    }
+  if (cand->pos == IP_END
+      && empty_block_p (ip_end_pos (data->current_loop)))
+    cand->cost++;
 }
 
 /* Determines costs of computation of the candidates.  */
@@ -3304,6 +4385,7 @@ determine_set_costs (struct ivopts_data *data)
   unsigned j, n;
   tree phi, op;
   struct loop *loop = data->current_loop;
+  bitmap_iterator bi;
 
   /* We use the following model (definitely improvable, especially the
      cost function -- TODO):
@@ -3334,308 +4416,783 @@ determine_set_costs (struct ivopts_data *data)
       fprintf (dump_file, "  target_spill_cost %d\n", target_spill_cost);
     }
 
-  n = 0;
-  for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
+  n = 0;
+  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
+    {
+      op = PHI_RESULT (phi);
+
+      if (!is_gimple_reg (op))
+       continue;
+
+      if (get_iv (data, op))
+       continue;
+
+      n++;
+    }
+
+  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, j, bi)
+    {
+      struct version_info *info = ver_info (data, j);
+
+      if (info->inv_id && info->has_nonlin_use)
+       n++;
+    }
+
+  loop_data (loop)->regs_used = n;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "  regs_used %d\n", n);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "  cost for size:\n");
+      fprintf (dump_file, "  ivs\tcost\n");
+      for (j = 0; j <= 2 * target_avail_regs; j++)
+       fprintf (dump_file, "  %d\t%d\n", j,
+                ivopts_global_cost_for_size (data, j));
+      fprintf (dump_file, "\n");
+    }
+}
+
+/* Returns true if A is a cheaper cost pair than B.  */
+
+static bool
+cheaper_cost_pair (struct cost_pair *a, struct cost_pair *b)
+{
+  if (!a)
+    return false;
+
+  if (!b)
+    return true;
+
+  if (a->cost < b->cost)
+    return true;
+
+  if (a->cost > b->cost)
+    return false;
+
+  /* In case the costs are the same, prefer the cheaper candidate.  */
+  if (a->cand->cost < b->cand->cost)
+    return true;
+
+  return false;
+}
+
+/* Computes the cost field of IVS structure.  */
+
+static void
+iv_ca_recount_cost (struct ivopts_data *data, struct iv_ca *ivs)
+{
+  unsigned cost = 0;
+
+  cost += ivs->cand_use_cost;
+  cost += ivs->cand_cost;
+  cost += ivopts_global_cost_for_size (data, ivs->n_regs);
+
+  ivs->cost = cost;
+}
+
+/* Remove invariants in set INVS to set IVS.  */
+
+static void
+iv_ca_set_remove_invariants (struct iv_ca *ivs, bitmap invs)
+{
+  bitmap_iterator bi;
+  unsigned iid;
+
+  if (!invs)
+    return;
+
+  EXECUTE_IF_SET_IN_BITMAP (invs, 0, iid, bi)
+    {
+      ivs->n_invariant_uses[iid]--;
+      if (ivs->n_invariant_uses[iid] == 0)
+       ivs->n_regs--;
+    }
+}
+
+/* Set USE not to be expressed by any candidate in IVS.  */
+
+static void
+iv_ca_set_no_cp (struct ivopts_data *data, struct iv_ca *ivs,
+                struct iv_use *use)
+{
+  unsigned uid = use->id, cid;
+  struct cost_pair *cp;
+
+  cp = ivs->cand_for_use[uid];
+  if (!cp)
+    return;
+  cid = cp->cand->id;
+
+  ivs->bad_uses++;
+  ivs->cand_for_use[uid] = NULL;
+  ivs->n_cand_uses[cid]--;
+
+  if (ivs->n_cand_uses[cid] == 0)
+    {
+      bitmap_clear_bit (ivs->cands, cid);
+      /* Do not count the pseudocandidates.  */
+      if (cp->cand->iv)
+       ivs->n_regs--;
+      ivs->n_cands--;
+      ivs->cand_cost -= cp->cand->cost;
+
+      iv_ca_set_remove_invariants (ivs, cp->cand->depends_on);
+    }
+
+  ivs->cand_use_cost -= cp->cost;
+
+  iv_ca_set_remove_invariants (ivs, cp->depends_on);
+  iv_ca_recount_cost (data, ivs);
+}
+
+/* Add invariants in set INVS to set IVS.  */
+
+static void
+iv_ca_set_add_invariants (struct iv_ca *ivs, bitmap invs)
+{
+  bitmap_iterator bi;
+  unsigned iid;
+
+  if (!invs)
+    return;
+
+  EXECUTE_IF_SET_IN_BITMAP (invs, 0, iid, bi)
+    {
+      ivs->n_invariant_uses[iid]++;
+      if (ivs->n_invariant_uses[iid] == 1)
+       ivs->n_regs++;
+    }
+}
+
+/* Set cost pair for USE in set IVS to CP.  */
+
+static void
+iv_ca_set_cp (struct ivopts_data *data, struct iv_ca *ivs,
+             struct iv_use *use, struct cost_pair *cp)
+{
+  unsigned uid = use->id, cid;
+
+  if (ivs->cand_for_use[uid] == cp)
+    return;
+
+  if (ivs->cand_for_use[uid])
+    iv_ca_set_no_cp (data, ivs, use);
+
+  if (cp)
+    {
+      cid = cp->cand->id;
+
+      ivs->bad_uses--;
+      ivs->cand_for_use[uid] = cp;
+      ivs->n_cand_uses[cid]++;
+      if (ivs->n_cand_uses[cid] == 1)
+       {
+         bitmap_set_bit (ivs->cands, cid);
+         /* Do not count the pseudocandidates.  */
+         if (cp->cand->iv)
+           ivs->n_regs++;
+         ivs->n_cands++;
+         ivs->cand_cost += cp->cand->cost;
+
+         iv_ca_set_add_invariants (ivs, cp->cand->depends_on);
+       }
+
+      ivs->cand_use_cost += cp->cost;
+      iv_ca_set_add_invariants (ivs, cp->depends_on);
+      iv_ca_recount_cost (data, ivs);
+    }
+}
+
+/* Extend set IVS by expressing USE by some of the candidates in it
+   if possible.  */
+
+static void
+iv_ca_add_use (struct ivopts_data *data, struct iv_ca *ivs,
+              struct iv_use *use)
+{
+  struct cost_pair *best_cp = NULL, *cp;
+  bitmap_iterator bi;
+  unsigned i;
+
+  gcc_assert (ivs->upto >= use->id);
+
+  if (ivs->upto == use->id)
+    {
+      ivs->upto++;
+      ivs->bad_uses++;
+    }
+
+  EXECUTE_IF_SET_IN_BITMAP (ivs->cands, 0, i, bi)
+    {
+      cp = get_use_iv_cost (data, use, iv_cand (data, i));
+
+      if (cheaper_cost_pair (cp, best_cp))
+       best_cp = cp;
+    }
+
+  iv_ca_set_cp (data, ivs, use, best_cp);
+}
+
+/* Get cost for assignment IVS.  */
+
+static unsigned
+iv_ca_cost (struct iv_ca *ivs)
+{
+  return (ivs->bad_uses ? INFTY : ivs->cost);
+}
+
+/* Returns true if all dependences of CP are among invariants in IVS.  */
+
+static bool
+iv_ca_has_deps (struct iv_ca *ivs, struct cost_pair *cp)
+{
+  unsigned i;
+  bitmap_iterator bi;
+
+  if (!cp->depends_on)
+    return true;
+
+  EXECUTE_IF_SET_IN_BITMAP (cp->depends_on, 0, i, bi)
+    {
+      if (ivs->n_invariant_uses[i] == 0)
+       return false;
+    }
+
+  return true;
+}
+
+/* Creates change of expressing USE by NEW_CP instead of OLD_CP and chains
+   it before NEXT_CHANGE.  */
+
+static struct iv_ca_delta *
+iv_ca_delta_add (struct iv_use *use, struct cost_pair *old_cp,
+                struct cost_pair *new_cp, struct iv_ca_delta *next_change)
+{
+  struct iv_ca_delta *change = XNEW (struct iv_ca_delta);
+
+  change->use = use;
+  change->old_cp = old_cp;
+  change->new_cp = new_cp;
+  change->next_change = next_change;
+
+  return change;
+}
+
+/* Joins two lists of changes L1 and L2.  Destructive -- old lists
+   are rewritten.  */
+
+static struct iv_ca_delta *
+iv_ca_delta_join (struct iv_ca_delta *l1, struct iv_ca_delta *l2)
+{
+  struct iv_ca_delta *last;
+
+  if (!l2)
+    return l1;
+
+  if (!l1)
+    return l2;
+
+  for (last = l1; last->next_change; last = last->next_change)
+    continue;
+  last->next_change = l2;
+
+  return l1;
+}
+
+/* Returns candidate by that USE is expressed in IVS.  */
+
+static struct cost_pair *
+iv_ca_cand_for_use (struct iv_ca *ivs, struct iv_use *use)
+{
+  return ivs->cand_for_use[use->id];
+}
+
+/* Reverse the list of changes DELTA, forming the inverse to it.  */
+
+static struct iv_ca_delta *
+iv_ca_delta_reverse (struct iv_ca_delta *delta)
+{
+  struct iv_ca_delta *act, *next, *prev = NULL;
+  struct cost_pair *tmp;
+
+  for (act = delta; act; act = next)
+    {
+      next = act->next_change;
+      act->next_change = prev;
+      prev = act;
+
+      tmp = act->old_cp;
+      act->old_cp = act->new_cp;
+      act->new_cp = tmp;
+    }
+
+  return prev;
+}
+
+/* Commit changes in DELTA to IVS.  If FORWARD is false, the changes are
+   reverted instead.  */
+
+static void
+iv_ca_delta_commit (struct ivopts_data *data, struct iv_ca *ivs,
+                   struct iv_ca_delta *delta, bool forward)
+{
+  struct cost_pair *from, *to;
+  struct iv_ca_delta *act;
+
+  if (!forward)
+    delta = iv_ca_delta_reverse (delta);
+
+  for (act = delta; act; act = act->next_change)
+    {
+      from = act->old_cp;
+      to = act->new_cp;
+      gcc_assert (iv_ca_cand_for_use (ivs, act->use) == from);
+      iv_ca_set_cp (data, ivs, act->use, to);
+    }
+
+  if (!forward)
+    iv_ca_delta_reverse (delta);
+}
+
+/* Returns true if CAND is used in IVS.  */
+
+static bool
+iv_ca_cand_used_p (struct iv_ca *ivs, struct iv_cand *cand)
+{
+  return ivs->n_cand_uses[cand->id] > 0;
+}
+
+/* Returns number of induction variable candidates in the set IVS.  */
+
+static unsigned
+iv_ca_n_cands (struct iv_ca *ivs)
+{
+  return ivs->n_cands;
+}
+
+/* Free the list of changes DELTA.  */
+
+static void
+iv_ca_delta_free (struct iv_ca_delta **delta)
+{
+  struct iv_ca_delta *act, *next;
+
+  for (act = *delta; act; act = next)
+    {
+      next = act->next_change;
+      free (act);
+    }
+
+  *delta = NULL;
+}
+
+/* Allocates new iv candidates assignment.  */
+
+static struct iv_ca *
+iv_ca_new (struct ivopts_data *data)
+{
+  struct iv_ca *nw = XNEW (struct iv_ca);
+
+  nw->upto = 0;
+  nw->bad_uses = 0;
+  nw->cand_for_use = XCNEWVEC (struct cost_pair *, n_iv_uses (data));
+  nw->n_cand_uses = XCNEWVEC (unsigned, n_iv_cands (data));
+  nw->cands = BITMAP_ALLOC (NULL);
+  nw->n_cands = 0;
+  nw->n_regs = 0;
+  nw->cand_use_cost = 0;
+  nw->cand_cost = 0;
+  nw->n_invariant_uses = XCNEWVEC (unsigned, data->max_inv_id + 1);
+  nw->cost = 0;
+
+  return nw;
+}
+
+/* Free memory occupied by the set IVS.  */
+
+static void
+iv_ca_free (struct iv_ca **ivs)
+{
+  free ((*ivs)->cand_for_use);
+  free ((*ivs)->n_cand_uses);
+  BITMAP_FREE ((*ivs)->cands);
+  free ((*ivs)->n_invariant_uses);
+  free (*ivs);
+  *ivs = NULL;
+}
+
+/* Dumps IVS to FILE.  */
+
+static void
+iv_ca_dump (struct ivopts_data *data, FILE *file, struct iv_ca *ivs)
+{
+  const char *pref = "  invariants ";
+  unsigned i;
+
+  fprintf (file, "  cost %d\n", iv_ca_cost (ivs));
+  bitmap_print (file, ivs->cands, "  candidates ","\n");
+
+  for (i = 1; i <= data->max_inv_id; i++)
+    if (ivs->n_invariant_uses[i])
+      {
+       fprintf (file, "%s%d", pref, i);
+       pref = ", ";
+      }
+  fprintf (file, "\n");
+}
+
+/* Try changing candidate in IVS to CAND for each use.  Return cost of the
+   new set, and store differences in DELTA.  Number of induction variables
+   in the new set is stored to N_IVS.  */
+
+static unsigned
+iv_ca_extend (struct ivopts_data *data, struct iv_ca *ivs,
+             struct iv_cand *cand, struct iv_ca_delta **delta,
+             unsigned *n_ivs)
+{
+  unsigned i, cost;
+  struct iv_use *use;
+  struct cost_pair *old_cp, *new_cp;
+
+  *delta = NULL;
+  for (i = 0; i < ivs->upto; i++)
     {
-      op = PHI_RESULT (phi);
+      use = iv_use (data, i);
+      old_cp = iv_ca_cand_for_use (ivs, use);
 
-      if (!is_gimple_reg (op))
+      if (old_cp
+         && old_cp->cand == cand)
        continue;
 
-      if (get_iv (data, op))
+      new_cp = get_use_iv_cost (data, use, cand);
+      if (!new_cp)
        continue;
 
-      n++;
-    }
-
-  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, j,
-    {
-      struct version_info *info = ver_info (data, j);
+      if (!iv_ca_has_deps (ivs, new_cp))
+       continue;
+      
+      if (!cheaper_cost_pair (new_cp, old_cp))
+       continue;
 
-      if (info->inv_id && info->has_nonlin_use)
-       n++;
-    });
+      *delta = iv_ca_delta_add (use, old_cp, new_cp, *delta);
+    }
 
-  loop_data (loop)->regs_used = n;
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "  regs_used %d\n", n);
+  iv_ca_delta_commit (data, ivs, *delta, true);
+  cost = iv_ca_cost (ivs);
+  if (n_ivs)
+    *n_ivs = iv_ca_n_cands (ivs);
+  iv_ca_delta_commit (data, ivs, *delta, false);
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "  cost for size:\n");
-      fprintf (dump_file, "  ivs\tcost\n");
-      for (j = 0; j <= 2 * target_avail_regs; j++)
-       fprintf (dump_file, "  %d\t%d\n", j,
-                ivopts_global_cost_for_size (data, j));
-      fprintf (dump_file, "\n");
-    }
+  return cost;
 }
 
-/* Finds a best candidate for USE and stores it to CAND.  The candidates are
-   taken from the set SOL and they may depend on invariants in the set INV.
-   The really used candidate and invariants are noted to USED_IVS and
-   USED_INV.  */
+/* Try narrowing set IVS by removing CAND.  Return the cost of
+   the new set and store the differences in DELTA.  */
 
 static unsigned
-find_best_candidate (struct ivopts_data *data,
-                    struct iv_use *use, bitmap sol, bitmap inv,
-                    bitmap used_ivs, bitmap used_inv, struct iv_cand **cand)
+iv_ca_narrow (struct ivopts_data *data, struct iv_ca *ivs,
+             struct iv_cand *cand, struct iv_ca_delta **delta)
 {
-  unsigned c, d;
-  unsigned best_cost = INFTY, cost;
-  struct iv_cand *cnd = NULL, *acnd;
-  bitmap depends_on = NULL, asol;
+  unsigned i, ci;
+  struct iv_use *use;
+  struct cost_pair *old_cp, *new_cp, *cp;
+  bitmap_iterator bi;
+  struct iv_cand *cnd;
+  unsigned cost;
 
-  if (data->consider_all_candidates)
-    asol = sol;
-  else
+  *delta = NULL;
+  for (i = 0; i < n_iv_uses (data); i++)
     {
-      asol = BITMAP_XMALLOC ();
-      bitmap_a_and_b (asol, sol, use->related_cands);
-    }
+      use = iv_use (data, i);
 
-  EXECUTE_IF_SET_IN_BITMAP (asol, 0, c,
-    {
-      acnd = iv_cand (data, c);
-      cost = get_use_iv_cost (data, use, acnd, &depends_on);
+      old_cp = iv_ca_cand_for_use (ivs, use);
+      if (old_cp->cand != cand)
+       continue;
 
-      if (cost == INFTY)
-       goto next_cand;
-      if (cost > best_cost)
-       goto next_cand;
-      if (cost == best_cost)
-       {
-         /* Prefer the cheaper iv.  */
-         if (acnd->cost >= cnd->cost)
-           goto next_cand;
-       }
+      new_cp = NULL;
 
-      if (depends_on)
+      if (data->consider_all_candidates)
        {
-         EXECUTE_IF_AND_COMPL_IN_BITMAP (depends_on, inv, 0, d,
-                                         goto next_cand);
-         if (used_inv)
-           bitmap_a_or_b (used_inv, used_inv, depends_on);
+         EXECUTE_IF_SET_IN_BITMAP (ivs->cands, 0, ci, bi)
+           {
+             if (ci == cand->id)
+               continue;
+
+             cnd = iv_cand (data, ci);
+
+             cp = get_use_iv_cost (data, use, cnd);
+             if (!cp)
+               continue;
+             if (!iv_ca_has_deps (ivs, cp))
+               continue;
+      
+             if (!cheaper_cost_pair (cp, new_cp))
+               continue;
+
+             new_cp = cp;
+           }
        }
+      else
+       {
+         EXECUTE_IF_AND_IN_BITMAP (use->related_cands, ivs->cands, 0, ci, bi)
+           {
+             if (ci == cand->id)
+               continue;
+
+             cnd = iv_cand (data, ci);
 
-      cnd = acnd;
-      best_cost = cost;
-next_cand: ;
-    });
+             cp = get_use_iv_cost (data, use, cnd);
+             if (!cp)
+               continue;
+             if (!iv_ca_has_deps (ivs, cp))
+               continue;
+      
+             if (!cheaper_cost_pair (cp, new_cp))
+               continue;
 
-  if (cnd && used_ivs)
-    bitmap_set_bit (used_ivs, cnd->id);
+             new_cp = cp;
+           }
+       }
+
+      if (!new_cp)
+       {
+         iv_ca_delta_free (delta);
+         return INFTY;
+       }
 
-  if (cand)
-    *cand = cnd;
+      *delta = iv_ca_delta_add (use, old_cp, new_cp, *delta);
+    }
 
-  if (!data->consider_all_candidates)
-    BITMAP_XFREE (asol);
+  iv_ca_delta_commit (data, ivs, *delta, true);
+  cost = iv_ca_cost (ivs);
+  iv_ca_delta_commit (data, ivs, *delta, false);
 
-  return best_cost;
+  return cost;
 }
 
-/* Returns cost of set of ivs SOL + invariants INV.  Removes unnecessary
-   induction variable candidates and invariants from the sets.  Only
-   uses 0 .. MAX_USE - 1 are taken into account.  */
+/* Try optimizing the set of candidates IVS by removing candidates different
+   from to EXCEPT_CAND from it.  Return cost of the new set, and store
+   differences in DELTA.  */
 
 static unsigned
-set_cost_up_to (struct ivopts_data *data, bitmap sol, bitmap inv,
-               unsigned max_use)
+iv_ca_prune (struct ivopts_data *data, struct iv_ca *ivs,
+            struct iv_cand *except_cand, struct iv_ca_delta **delta)
 {
-  unsigned i;
-  unsigned cost = 0, size = 0, acost;
-  struct iv_use *use;
+  bitmap_iterator bi;
+  struct iv_ca_delta *act_delta, *best_delta;
+  unsigned i, best_cost, acost;
   struct iv_cand *cand;
-  bitmap used_ivs = BITMAP_XMALLOC (), used_inv = BITMAP_XMALLOC ();
 
-  for (i = 0; i < max_use; i++)
-    {
-      use = iv_use (data, i);
-      acost = find_best_candidate (data, use, sol, inv,
-                                  used_ivs, used_inv, NULL);
-      if (acost == INFTY)
-       {
-         BITMAP_XFREE (used_ivs);
-         BITMAP_XFREE (used_inv);
-         return INFTY;
-       }
-      cost += acost;
-    }
+  best_delta = NULL;
+  best_cost = iv_ca_cost (ivs);
 
-  EXECUTE_IF_SET_IN_BITMAP (used_ivs, 0, i,
+  EXECUTE_IF_SET_IN_BITMAP (ivs->cands, 0, i, bi)
     {
       cand = iv_cand (data, i);
 
-      /* Do not count the pseudocandidates.  */
-      if (cand->iv)
-       size++;
-
-      cost += cand->cost;
-    });
-  EXECUTE_IF_SET_IN_BITMAP (used_inv, 0, i, size++);
-  cost += ivopts_global_cost_for_size (data, size);
-
-  bitmap_copy (sol, used_ivs);
-  bitmap_copy (inv, used_inv);
+      if (cand == except_cand)
+       continue;
 
-  BITMAP_XFREE (used_ivs);
-  BITMAP_XFREE (used_inv);
+      acost = iv_ca_narrow (data, ivs, cand, &act_delta);
 
-  return cost;
-}
+      if (acost < best_cost)
+       {
+         best_cost = acost;
+         iv_ca_delta_free (&best_delta);
+         best_delta = act_delta;
+       }
+      else
+       iv_ca_delta_free (&act_delta);
+    }
 
-/* Computes cost of set of ivs SOL + invariants INV.  Removes unnecessary
-   induction variable candidates and invariants from the sets.  */
+  if (!best_delta)
+    {
+      *delta = NULL;
+      return best_cost;
+    }
 
-static unsigned
-set_cost (struct ivopts_data *data, bitmap sol, bitmap inv)
-{
-  return set_cost_up_to (data, sol, inv, n_iv_uses (data));
+  /* Recurse to possibly remove other unnecessary ivs.  */
+  iv_ca_delta_commit (data, ivs, best_delta, true);
+  best_cost = iv_ca_prune (data, ivs, except_cand, delta);
+  iv_ca_delta_commit (data, ivs, best_delta, false);
+  *delta = iv_ca_delta_join (best_delta, *delta);
+  return best_cost;
 }
 
-/* Tries to extend the sets IVS and INV in the best possible way in order
+/* Tries to extend the sets IVS in the best possible way in order
    to express the USE.  */
 
 static bool
-try_add_cand_for (struct ivopts_data *data, bitmap ivs, bitmap inv,
+try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs,
                  struct iv_use *use)
 {
-  unsigned best_cost = set_cost_up_to (data, ivs, inv, use->id + 1), act_cost;
-  bitmap best_ivs = BITMAP_XMALLOC ();
-  bitmap best_inv = BITMAP_XMALLOC ();
-  bitmap act_ivs = BITMAP_XMALLOC ();
-  bitmap act_inv = BITMAP_XMALLOC ();
+  unsigned best_cost, act_cost;
   unsigned i;
+  bitmap_iterator bi;
+  struct iv_cand *cand;
+  struct iv_ca_delta *best_delta = NULL, *act_delta;
   struct cost_pair *cp;
 
-  bitmap_copy (best_ivs, ivs);
-  bitmap_copy (best_inv, inv);
+  iv_ca_add_use (data, ivs, use);
+  best_cost = iv_ca_cost (ivs);
+
+  cp = iv_ca_cand_for_use (ivs, use);
+  if (cp)
+    {
+      best_delta = iv_ca_delta_add (use, NULL, cp, NULL);
+      iv_ca_set_no_cp (data, ivs, use);
+    }
 
-  for (i = 0; i < use->n_map_members; i++)
+  /* First try important candidates.  Only if it fails, try the specific ones.
+     Rationale -- in loops with many variables the best choice often is to use
+     just one generic biv.  If we added here many ivs specific to the uses,
+     the optimization algorithm later would be likely to get stuck in a local
+     minimum, thus causing us to create too many ivs.  The approach from
+     few ivs to more seems more likely to be successful -- starting from few
+     ivs, replacing an expensive use by a specific iv should always be a
+     win.  */
+  EXECUTE_IF_SET_IN_BITMAP (data->important_candidates, 0, i, bi)
     {
-      cp = use->cost_map + i;
-      if (cp->cost == INFTY)
+      cand = iv_cand (data, i);
+
+      if (iv_ca_cand_used_p (ivs, cand))
        continue;
 
-      bitmap_copy (act_ivs, ivs);
-      bitmap_set_bit (act_ivs, cp->cand->id);
-      if (cp->depends_on)
-       bitmap_a_or_b (act_inv, inv, cp->depends_on);
-      else
-       bitmap_copy (act_inv, inv);
-      act_cost = set_cost_up_to (data, act_ivs, act_inv, use->id + 1);
+      cp = get_use_iv_cost (data, use, cand);
+      if (!cp)
+       continue;
+
+      iv_ca_set_cp (data, ivs, use, cp);
+      act_cost = iv_ca_extend (data, ivs, cand, &act_delta, NULL);
+      iv_ca_set_no_cp (data, ivs, use);
+      act_delta = iv_ca_delta_add (use, NULL, cp, act_delta);
 
       if (act_cost < best_cost)
        {
          best_cost = act_cost;
-         bitmap_copy (best_ivs, act_ivs);
-         bitmap_copy (best_inv, act_inv);
+
+         iv_ca_delta_free (&best_delta);
+         best_delta = act_delta;
        }
+      else
+       iv_ca_delta_free (&act_delta);
     }
 
-  bitmap_copy (ivs, best_ivs);
-  bitmap_copy (inv, best_inv);
+  if (best_cost == INFTY)
+    {
+      for (i = 0; i < use->n_map_members; i++)
+       {
+         cp = use->cost_map + i;
+         cand = cp->cand;
+         if (!cand)
+           continue;
+
+         /* Already tried this.  */
+         if (cand->important)
+           continue;
+      
+         if (iv_ca_cand_used_p (ivs, cand))
+           continue;
+
+         act_delta = NULL;
+         iv_ca_set_cp (data, ivs, use, cp);
+         act_cost = iv_ca_extend (data, ivs, cand, &act_delta, NULL);
+         iv_ca_set_no_cp (data, ivs, use);
+         act_delta = iv_ca_delta_add (use, iv_ca_cand_for_use (ivs, use),
+                                      cp, act_delta);
+
+         if (act_cost < best_cost)
+           {
+             best_cost = act_cost;
+
+             if (best_delta)
+               iv_ca_delta_free (&best_delta);
+             best_delta = act_delta;
+           }
+         else
+           iv_ca_delta_free (&act_delta);
+       }
+    }
 
-  BITMAP_XFREE (best_ivs);
-  BITMAP_XFREE (best_inv);
-  BITMAP_XFREE (act_ivs);
-  BITMAP_XFREE (act_inv);
+  iv_ca_delta_commit (data, ivs, best_delta, true);
+  iv_ca_delta_free (&best_delta);
 
   return (best_cost != INFTY);
 }
 
-/* Finds an initial set of IVS and invariants INV.  We do this by simply
-   choosing the best candidate for each use.  */
+/* Finds an initial assignment of candidates to uses.  */
 
-static unsigned
-get_initial_solution (struct ivopts_data *data, bitmap ivs, bitmap inv)
+static struct iv_ca *
+get_initial_solution (struct ivopts_data *data)
 {
+  struct iv_ca *ivs = iv_ca_new (data);
   unsigned i;
 
   for (i = 0; i < n_iv_uses (data); i++)
-    if (!try_add_cand_for (data, ivs, inv, iv_use (data, i)))
-      return INFTY;
+    if (!try_add_cand_for (data, ivs, iv_use (data, i)))
+      {
+       iv_ca_free (&ivs);
+       return NULL;
+      }
 
-  return set_cost (data, ivs, inv);
+  return ivs;
 }
 
-/* Tries to improve set of induction variables IVS and invariants INV to get
-   it better than COST.  */
+/* Tries to improve set of induction variables IVS.  */
 
 static bool
-try_improve_iv_set (struct ivopts_data *data,
-                   bitmap ivs, bitmap inv, unsigned *cost)
+try_improve_iv_set (struct ivopts_data *data, struct iv_ca *ivs)
 {
-  unsigned i, acost;
-  bitmap new_ivs = BITMAP_XMALLOC (), new_inv = BITMAP_XMALLOC ();
-  bitmap best_new_ivs = NULL, best_new_inv = NULL;
+  unsigned i, acost, best_cost = iv_ca_cost (ivs), n_ivs;
+  struct iv_ca_delta *best_delta = NULL, *act_delta, *tmp_delta;
+  struct iv_cand *cand;
 
-  /* Try altering the set of induction variables by one.  */
+  /* Try extending the set of induction variables by one.  */
   for (i = 0; i < n_iv_cands (data); i++)
     {
-      bitmap_copy (new_ivs, ivs);
-      bitmap_copy (new_inv, inv);
-
-      if (bitmap_bit_p (ivs, i))
-       bitmap_clear_bit (new_ivs, i);
-      else
-       bitmap_set_bit (new_ivs, i);
-
-      acost = set_cost (data, new_ivs, new_inv);
-      if (acost >= *cost)
+      cand = iv_cand (data, i);
+      
+      if (iv_ca_cand_used_p (ivs, cand))
        continue;
 
-      if (!best_new_ivs)
-       {
-         best_new_ivs = BITMAP_XMALLOC ();
-         best_new_inv = BITMAP_XMALLOC ();
-       }
-
-      *cost = acost;
-      bitmap_copy (best_new_ivs, new_ivs);
-      bitmap_copy (best_new_inv, new_inv);
-    }
-
-  /* Ditto for invariants.  */
-  for (i = 1; i <= data->max_inv_id; i++)
-    {
-      if (ver_info (data, i)->has_nonlin_use)
+      acost = iv_ca_extend (data, ivs, cand, &act_delta, &n_ivs);
+      if (!act_delta)
        continue;
 
-      bitmap_copy (new_ivs, ivs);
-      bitmap_copy (new_inv, inv);
-
-      if (bitmap_bit_p (inv, i))
-       bitmap_clear_bit (new_inv, i);
-      else
-       bitmap_set_bit (new_inv, i);
-
-      acost = set_cost (data, new_ivs, new_inv);
-      if (acost >= *cost)
-       continue;
+      /* If we successfully added the candidate and the set is small enough,
+        try optimizing it by removing other candidates.  */
+      if (n_ivs <= ALWAYS_PRUNE_CAND_SET_BOUND)
+       {
+         iv_ca_delta_commit (data, ivs, act_delta, true);
+         acost = iv_ca_prune (data, ivs, cand, &tmp_delta);
+         iv_ca_delta_commit (data, ivs, act_delta, false);
+         act_delta = iv_ca_delta_join (act_delta, tmp_delta);
+       }
 
-      if (!best_new_ivs)
+      if (acost < best_cost)
        {
-         best_new_ivs = BITMAP_XMALLOC ();
-         best_new_inv = BITMAP_XMALLOC ();
+         best_cost = acost;
+         iv_ca_delta_free (&best_delta);
+         best_delta = act_delta;
        }
-
-      *cost = acost;
-      bitmap_copy (best_new_ivs, new_ivs);
-      bitmap_copy (best_new_inv, new_inv);
+      else
+       iv_ca_delta_free (&act_delta);
     }
 
-  BITMAP_XFREE (new_ivs);
-  BITMAP_XFREE (new_inv);
+  if (!best_delta)
+    {
+      /* Try removing the candidates from the set instead.  */
+      best_cost = iv_ca_prune (data, ivs, NULL, &best_delta);
 
-  if (!best_new_ivs)
-    return false;
+      /* Nothing more we can do.  */
+      if (!best_delta)
+       return false;
+    }
 
-  bitmap_copy (ivs, best_new_ivs);
-  bitmap_copy (inv, best_new_inv);
-  BITMAP_XFREE (best_new_ivs);
-  BITMAP_XFREE (best_new_inv);
+  iv_ca_delta_commit (data, ivs, best_delta, true);
+  gcc_assert (best_cost == iv_ca_cost (ivs));
+  iv_ca_delta_free (&best_delta);
   return true;
 }
 
@@ -3643,57 +5200,46 @@ try_improve_iv_set (struct ivopts_data *data,
    greedy heuristic -- we try to replace at most one candidate in the selected
    solution and remove the unused ivs while this improves the cost.  */
 
-static bitmap
+static struct iv_ca *
 find_optimal_iv_set (struct ivopts_data *data)
 {
-  unsigned cost, i;
-  bitmap set = BITMAP_XMALLOC ();
-  bitmap inv = BITMAP_XMALLOC ();
+  unsigned i;
+  struct iv_ca *set;
   struct iv_use *use;
 
-  /* Set the upper bound.  */
-  cost = get_initial_solution (data, set, inv);
-  if (cost == INFTY)
+  /* Get the initial solution.  */
+  set = get_initial_solution (data);
+  if (!set)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Unable to substitute for ivs, failed.\n");
-      BITMAP_XFREE (inv);
-      BITMAP_XFREE (set);
       return NULL;
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      fprintf (dump_file, "Initial set of candidates (cost %d): ", cost);
-      bitmap_print (dump_file, set, "", "");
-      fprintf (dump_file, " invariants ");
-      bitmap_print (dump_file, inv, "", "");
-      fprintf (dump_file, "\n");
+      fprintf (dump_file, "Initial set of candidates:\n");
+      iv_ca_dump (data, dump_file, set);
     }
 
-  while (try_improve_iv_set (data, set, inv, &cost))
+  while (try_improve_iv_set (data, set))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
-         fprintf (dump_file, "Improved to (cost %d): ", cost);
-         bitmap_print (dump_file, set, "", "");
-         fprintf (dump_file, " invariants ");
-         bitmap_print (dump_file, inv, "", "");
-         fprintf (dump_file, "\n");
+         fprintf (dump_file, "Improved to:\n");
+         iv_ca_dump (data, dump_file, set);
        }
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Final cost %d\n\n", cost);
+    fprintf (dump_file, "Final cost %d\n\n", iv_ca_cost (set));
 
   for (i = 0; i < n_iv_uses (data); i++)
     {
       use = iv_use (data, i);
-      find_best_candidate (data, use, set, inv, NULL, NULL, &use->selected);
+      use->selected = iv_ca_cand_for_use (set, use)->cand;
     }
 
-  BITMAP_XFREE (inv);
-
   return set;
 }
 
@@ -3736,23 +5282,25 @@ create_new_iv (struct ivopts_data *data, struct iv_cand *cand)
 
   base = unshare_expr (cand->iv->base);
 
-  create_iv (base, cand->iv->step, cand->var_before, data->current_loop,
+  create_iv (base, unshare_expr (cand->iv->step),
+            cand->var_before, data->current_loop,
             &incr_pos, after, &cand->var_before, &cand->var_after);
 }
 
 /* Creates new induction variables described in SET.  */
 
 static void
-create_new_ivs (struct ivopts_data *data, bitmap set)
+create_new_ivs (struct ivopts_data *data, struct iv_ca *set)
 {
   unsigned i;
   struct iv_cand *cand;
+  bitmap_iterator bi;
 
-  EXECUTE_IF_SET_IN_BITMAP (set, 0, i,
+  EXECUTE_IF_SET_IN_BITMAP (set->cands, 0, i, bi)
     {
       cand = iv_cand (data, i);
       create_new_iv (data, cand);
-    });
+    }
 }
 
 /* Removes statement STMT (real or a phi node).  If INCLUDING_DEFINED_NAME
@@ -3768,13 +5316,13 @@ remove_statement (tree stmt, bool including_defined_name)
          /* Prevent the ssa name defined by the statement from being removed.  */
          SET_PHI_RESULT (stmt, NULL);
        }
-      remove_phi_node (stmt, NULL_TREE, bb_for_stmt (stmt));
+      remove_phi_node (stmt, NULL_TREE);
     }
   else
     {
-      block_stmt_iterator bsi = stmt_for_bsi (stmt);
+      block_stmt_iterator bsi = bsi_for_stmt (stmt);
 
-      bsi_remove (&bsi);
+      bsi_remove (&bsi, true);
     }
 }
 
@@ -3785,13 +5333,70 @@ static void
 rewrite_use_nonlinear_expr (struct ivopts_data *data,
                            struct iv_use *use, struct iv_cand *cand)
 {
-  tree comp = unshare_expr (get_computation (data->current_loop,
-                                            use, cand));
+  tree comp;
   tree op, stmts, tgt, ass;
   block_stmt_iterator bsi, pbsi;
-  if (TREE_CODE (use->stmt) == PHI_NODE)
+
+  /* An important special case -- if we are asked to express value of
+     the original iv by itself, just exit; there is no need to
+     introduce a new computation (that might also need casting the
+     variable to unsigned and back).  */
+  if (cand->pos == IP_ORIGINAL
+      && cand->incremented_at == use->stmt)
+    {
+      tree step, ctype, utype;
+      enum tree_code incr_code = PLUS_EXPR;
+
+      gcc_assert (TREE_CODE (use->stmt) == MODIFY_EXPR);
+      gcc_assert (TREE_OPERAND (use->stmt, 0) == cand->var_after);
+
+      step = cand->iv->step;
+      ctype = TREE_TYPE (step);
+      utype = TREE_TYPE (cand->var_after);
+      if (TREE_CODE (step) == NEGATE_EXPR)
+       {
+         incr_code = MINUS_EXPR;
+         step = TREE_OPERAND (step, 0);
+       }
+
+      /* Check whether we may leave the computation unchanged.
+        This is the case only if it does not rely on other
+        computations in the loop -- otherwise, the computation
+        we rely upon may be removed in remove_unused_ivs,
+        thus leading to ICE.  */
+      op = TREE_OPERAND (use->stmt, 1);
+      if (TREE_CODE (op) == PLUS_EXPR
+         || TREE_CODE (op) == MINUS_EXPR)
+       {
+         if (TREE_OPERAND (op, 0) == cand->var_before)
+           op = TREE_OPERAND (op, 1);
+         else if (TREE_CODE (op) == PLUS_EXPR
+                  && TREE_OPERAND (op, 1) == cand->var_before)
+           op = TREE_OPERAND (op, 0);
+         else
+           op = NULL_TREE;
+       }
+      else
+       op = NULL_TREE;
+
+      if (op
+         && (TREE_CODE (op) == INTEGER_CST
+             || operand_equal_p (op, step, 0)))
+       return;
+
+      /* Otherwise, add the necessary computations to express
+        the iv.  */
+      op = fold_convert (ctype, cand->var_before);
+      comp = fold_convert (utype,
+                          build2 (incr_code, ctype, op,
+                                  unshare_expr (step)));
+    }
+  else
+    comp = get_computation (data->current_loop, use, cand);
+
+  switch (TREE_CODE (use->stmt))
     {
+    case PHI_NODE:
       tgt = PHI_RESULT (use->stmt);
 
       /* If we should keep the biv, do not replace it.  */
@@ -3805,14 +5410,16 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data,
          bsi = pbsi;
          bsi_next (&pbsi);
        }
-    }
-  else if (TREE_CODE (use->stmt) == MODIFY_EXPR)
-    {
+      break;
+
+    case MODIFY_EXPR:
       tgt = TREE_OPERAND (use->stmt, 0);
-      bsi = stmt_for_bsi (use->stmt);
+      bsi = bsi_for_stmt (use->stmt);
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  else
-    abort ();
 
   op = force_gimple_operand (comp, &stmts, false, SSA_NAME_VAR (tgt));
 
@@ -3837,11 +5444,26 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data,
    for_each_index.  */
 
 static bool
-idx_remove_ssa_names (tree base ATTRIBUTE_UNUSED, tree *idx,
+idx_remove_ssa_names (tree base, tree *idx,
                      void *data ATTRIBUTE_UNUSED)
 {
+  tree *op;
+
   if (TREE_CODE (*idx) == SSA_NAME)
     *idx = SSA_NAME_VAR (*idx);
+
+  if (TREE_CODE (base) == ARRAY_REF)
+    {
+      op = &TREE_OPERAND (base, 2);
+      if (*op
+         && TREE_CODE (*op) == SSA_NAME)
+       *op = SSA_NAME_VAR (*op);
+      op = &TREE_OPERAND (base, 3);
+      if (*op
+         && TREE_CODE (*op) == SSA_NAME)
+       *op = SSA_NAME_VAR (*op);
+    }
+
   return true;
 }
 
@@ -3856,63 +5478,78 @@ unshare_and_remove_ssa_names (tree ref)
   return ref;
 }
 
-/* Rewrites base of memory access OP with expression WITH in statement
-   pointed to by BSI.  */
+/* Extract the alias analysis info for the memory reference REF.  There are
+   several ways how this information may be stored and what precisely is
+   its semantics depending on the type of the reference, but there always is
+   somewhere hidden one _DECL node that is used to determine the set of
+   virtual operands for the reference.  The code below deciphers this jungle
+   and extracts this single useful piece of information.  */
 
-static void
-rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
+static tree
+get_ref_tag (tree ref, tree orig)
 {
-  tree var = get_base_address (*op), new_var, new_name, copy, name;
-  tree orig;
+  tree var = get_base_address (ref);
+  tree aref = NULL_TREE, tag, sv;
+  HOST_WIDE_INT offset, size, maxsize;
+
+  for (sv = orig; handled_component_p (sv); sv = TREE_OPERAND (sv, 0))
+    {
+      aref = get_ref_base_and_extent (sv, &offset, &size, &maxsize);
+      if (ref)
+       break;
+    }
+
+  if (aref && SSA_VAR_P (aref) && get_subvars_for_var (aref))
+    return unshare_expr (sv);
 
-  if (!var || TREE_CODE (with) != SSA_NAME)
-    goto do_rewrite;
+  if (!var)
+    return NULL_TREE;
 
   if (TREE_CODE (var) == INDIRECT_REF)
-    var = TREE_OPERAND (var, 0);
-  if (TREE_CODE (var) == SSA_NAME)
     {
-      name = var;
+      /* In case the base is a dereference of a pointer, first check its name
+        mem tag, and if it does not have one, use type mem tag.  */
+      var = TREE_OPERAND (var, 0);
+      if (TREE_CODE (var) != SSA_NAME)
+       return NULL_TREE;
+
+      if (SSA_NAME_PTR_INFO (var))
+       {
+         tag = SSA_NAME_PTR_INFO (var)->name_mem_tag;
+         if (tag)
+           return tag;
+       }
       var = SSA_NAME_VAR (var);
+      tag = var_ann (var)->type_mem_tag;
+      gcc_assert (tag != NULL_TREE);
+      return tag;
     }
-  else if (DECL_P (var))
-    name = NULL_TREE;
-  else
-    goto do_rewrite;
-    
-  if (var_ann (var)->type_mem_tag)
-    var = var_ann (var)->type_mem_tag;
-
-  /* We need to add a memory tag for the variable.  But we do not want
-     to add it to the temporary used for the computations, since this leads
-     to problems in redundancy elimination when there are common parts
-     in two computations referring to the different arrays.  So we copy
-     the variable to a new temporary.  */
-  copy = build2 (MODIFY_EXPR, void_type_node, NULL_TREE, with);
-  if (name)
-    new_name = duplicate_ssa_name (name, copy);
   else
-    {
-      new_var = create_tmp_var (TREE_TYPE (with), "ruatmp");
-      add_referenced_tmp_var (new_var);
-      var_ann (new_var)->type_mem_tag = var;
-      new_name = make_ssa_name (new_var, copy);
-    }
-  TREE_OPERAND (copy, 0) = new_name;
-  bsi_insert_before (bsi, copy, BSI_SAME_STMT);
-  with = new_name;
+    { 
+      if (!DECL_P (var))
+       return NULL_TREE;
+
+      tag = var_ann (var)->type_mem_tag;
+      if (tag)
+       return tag;
 
-do_rewrite:
+      return var;
+    }
+}
 
-  orig = NULL_TREE;
-  if (TREE_CODE (*op) == INDIRECT_REF)
-    orig = REF_ORIGINAL (*op);
-  if (!orig)
-    orig = unshare_and_remove_ssa_names (*op);
+/* Copies the reference information from OLD_REF to NEW_REF.  */
 
-  *op = build1 (INDIRECT_REF, TREE_TYPE (*op), with);
-  /* Record the original reference, for purposes of alias analysis.  */
-  REF_ORIGINAL (*op) = orig;
+static void
+copy_ref_info (tree new_ref, tree old_ref)
+{
+  if (TREE_CODE (old_ref) == TARGET_MEM_REF)
+    copy_mem_ref_info (new_ref, old_ref);
+  else
+    {
+      TMR_ORIGINAL (new_ref) = unshare_and_remove_ssa_names (old_ref);
+      TMR_TAG (new_ref) = get_ref_tag (old_ref, TMR_ORIGINAL (new_ref));
+    }
 }
 
 /* Rewrites USE (address that is an iv) using candidate CAND.  */
@@ -3921,16 +5558,16 @@ static void
 rewrite_use_address (struct ivopts_data *data,
                     struct iv_use *use, struct iv_cand *cand)
 {
-  tree comp = unshare_expr (get_computation (data->current_loop,
-                                            use, cand));
-  block_stmt_iterator bsi = stmt_for_bsi (use->stmt);
-  tree stmts;
-  tree op = force_gimple_operand (comp, &stmts, true, NULL_TREE);
+  struct affine_tree_combination aff;
+  block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
+  tree ref;
 
-  if (stmts)
-    bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
+  get_computation_aff (data->current_loop, use, cand, use->stmt, &aff);
+  unshare_aff_combination (&aff);
 
-  rewrite_address_base (&bsi, use->op_p, op);
+  ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff);
+  copy_ref_info (ref, *use->op_p);
+  *use->op_p = ref;
 }
 
 /* Rewrites USE (the condition such that one of the arguments is an iv) using
@@ -3942,28 +5579,32 @@ rewrite_use_compare (struct ivopts_data *data,
 {
   tree comp;
   tree *op_p, cond, op, stmts, bound;
-  block_stmt_iterator bsi = stmt_for_bsi (use->stmt);
+  block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
   enum tree_code compare;
+  struct cost_pair *cp = get_use_iv_cost (data, use, cand);
   
-  if (may_eliminate_iv (data->current_loop,
-                       use, cand, &compare, &bound))
+  bound = cp->value;
+  if (bound)
     {
+      tree var = var_at_stmt (data->current_loop, cand, use->stmt);
+      tree var_type = TREE_TYPE (var);
+
+      compare = iv_elimination_compare (data, use);
+      bound = fold_convert (var_type, bound);
       op = force_gimple_operand (unshare_expr (bound), &stmts,
                                 true, NULL_TREE);
 
       if (stmts)
        bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
 
-      *use->op_p = build2 (compare, boolean_type_node,
-                         var_at_stmt (data->current_loop,
-                                      cand, use->stmt), op);
-      modify_stmt (use->stmt);
+      *use->op_p = build2 (compare, boolean_type_node, var, op);
+      update_stmt (use->stmt);
       return;
     }
 
   /* The induction variable elimination failed; just express the original
      giv.  */
-  comp = unshare_expr (get_computation (data->current_loop, use, cand));
+  comp = get_computation (data->current_loop, use, cand);
 
   cond = *use->op_p;
   op_p = &TREE_OPERAND (cond, 0);
@@ -4001,7 +5642,7 @@ protect_loop_closed_ssa_form_use (edge exit, use_operand_p op_p)
     return;
 
   /* Try finding a phi node that copies the value out of the loop.  */
-  for (phi = phi_nodes (exit->dest); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (exit->dest); phi; phi = PHI_CHAIN (phi))
     if (PHI_ARG_DEF_FROM_EDGE (phi, exit) == use)
       break;
 
@@ -4012,7 +5653,7 @@ protect_loop_closed_ssa_form_use (edge exit, use_operand_p op_p)
 
       phi = create_phi_node (new_name, exit->dest);
       SSA_NAME_DEF_STMT (new_name) = phi;
-      add_phi_arg (&phi, use, exit);
+      add_phi_arg (phi, use, exit);
     }
 
   SET_USE (op_p, PHI_RESULT (phi));
@@ -4024,60 +5665,53 @@ protect_loop_closed_ssa_form_use (edge exit, use_operand_p op_p)
 static void
 protect_loop_closed_ssa_form (edge exit, tree stmt)
 {
-  use_optype uses;
-  vuse_optype vuses;
-  v_may_def_optype v_may_defs;
-  unsigned i;
-
-  get_stmt_operands (stmt);
-
-  uses = STMT_USE_OPS (stmt);
-  for (i = 0; i < NUM_USES (uses); i++)
-    protect_loop_closed_ssa_form_use (exit, USE_OP_PTR (uses, i));
-
-  vuses = STMT_VUSE_OPS (stmt);
-  for (i = 0; i < NUM_VUSES (vuses); i++)
-    protect_loop_closed_ssa_form_use (exit, VUSE_OP_PTR (vuses, i));
+  ssa_op_iter iter;
+  use_operand_p use_p;
 
-  v_may_defs = STMT_V_MAY_DEF_OPS (stmt);
-  for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
-    protect_loop_closed_ssa_form_use (exit, V_MAY_DEF_OP_PTR (v_may_defs, i));
+  FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
+    protect_loop_closed_ssa_form_use (exit, use_p);
 }
 
 /* STMTS compute a value of a phi argument OP on EXIT of a loop.  Arrange things
    so that they are emitted on the correct place, and so that the loop closed
    ssa form is preserved.  */
 
-static void
+void
 compute_phi_arg_on_exit (edge exit, tree stmts, tree op)
 {
   tree_stmt_iterator tsi;
   block_stmt_iterator bsi;
   tree phi, stmt, def, next;
 
-  if (exit->dest->pred->pred_next)
+  if (!single_pred_p (exit->dest))
     split_loop_exit_edge (exit);
 
+  /* Ensure there is label in exit->dest, so that we can
+     insert after it.  */
+  tree_block_label (exit->dest);
+  bsi = bsi_after_labels (exit->dest);
+
   if (TREE_CODE (stmts) == STATEMENT_LIST)
     {
       for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
-       protect_loop_closed_ssa_form (exit, tsi_stmt (tsi));
+        {
+         tree stmt = tsi_stmt (tsi);
+         bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
+         protect_loop_closed_ssa_form (exit, stmt);
+       }
     }
   else
-    protect_loop_closed_ssa_form (exit, stmts);
-
-  /* Ensure there is label in exit->dest, so that we can
-     insert after it.  */
-  tree_block_label (exit->dest);
-  bsi = bsi_after_labels (exit->dest);
-  bsi_insert_after (&bsi, stmts, BSI_CONTINUE_LINKING);
+    {
+      bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
+      protect_loop_closed_ssa_form (exit, stmts);
+    }
 
   if (!op)
     return;
 
   for (phi = phi_nodes (exit->dest); phi; phi = next)
     {
-      next = TREE_CHAIN (phi);
+      next = PHI_CHAIN (phi);
 
       if (PHI_ARG_DEF_FROM_EDGE (phi, exit) == op)
        {
@@ -4086,7 +5720,7 @@ compute_phi_arg_on_exit (edge exit, tree stmts, tree op)
          stmt = build2 (MODIFY_EXPR, TREE_TYPE (op),
                        def, op);
          SSA_NAME_DEF_STMT (def) = stmt;
-         bsi_insert_after (&bsi, stmt, BSI_CONTINUE_LINKING);
+         bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
        }
     }
 }
@@ -4102,20 +5736,26 @@ rewrite_use_outer (struct ivopts_data *data,
   tree value, op, stmts, tgt;
   tree phi;
 
-  if (TREE_CODE (use->stmt) == PHI_NODE)
-    tgt = PHI_RESULT (use->stmt);
-  else if (TREE_CODE (use->stmt) == MODIFY_EXPR)
-    tgt = TREE_OPERAND (use->stmt, 0);
-  else
-    abort ();
+  switch (TREE_CODE (use->stmt))
+    {
+    case PHI_NODE:
+      tgt = PHI_RESULT (use->stmt);
+      break;
+    case MODIFY_EXPR:
+      tgt = TREE_OPERAND (use->stmt, 0);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
   exit = single_dom_exit (data->current_loop);
 
   if (exit)
     {
       if (!cand->iv)
        {
-         if (!may_replace_final_value (data->current_loop, use, &value))
-           abort ();
+         struct cost_pair *cp = get_use_iv_cost (data, use, cand);
+         value = unshare_expr (cp->value);
        }
       else
        value = get_computation_at (data->current_loop,
@@ -4128,7 +5768,7 @@ rewrite_use_outer (struct ivopts_data *data,
       if (stmts && name_info (data, tgt)->preserve_biv)
        return;
 
-      for (phi = phi_nodes (exit->dest); phi; phi = TREE_CHAIN (phi))
+      for (phi = phi_nodes (exit->dest); phi; phi = PHI_CHAIN (phi))
        {
          use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, exit);
 
@@ -4180,9 +5820,9 @@ rewrite_use (struct ivopts_data *data,
        break;
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
-  modify_stmt (use->stmt);
+  mark_new_vars_to_rename (use->stmt);
 }
 
 /* Rewrite the uses using the selected induction variables.  */
@@ -4198,8 +5838,7 @@ rewrite_uses (struct ivopts_data *data)
     {
       use = iv_use (data, i);
       cand = use->selected;
-      if (!cand)
-       abort ();
+      gcc_assert (cand);
 
       rewrite_use (data, use, cand);
     }
@@ -4211,8 +5850,9 @@ static void
 remove_unused_ivs (struct ivopts_data *data)
 {
   unsigned j;
+  bitmap_iterator bi;
 
-  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, j,
+  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, j, bi)
     {
       struct version_info *info;
 
@@ -4223,7 +5863,7 @@ remove_unused_ivs (struct ivopts_data *data)
          && !info->iv->have_use_for
          && !info->preserve_biv)
        remove_statement (SSA_NAME_DEF_STMT (info->iv->ssa_name), true);
-    });
+    }
 }
 
 /* Frees data allocated by the optimization of a single loop.  */
@@ -4232,8 +5872,12 @@ static void
 free_loop_data (struct ivopts_data *data)
 {
   unsigned i, j;
+  bitmap_iterator bi;
+  tree obj;
 
-  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i,
+  htab_empty (data->niters);
+
+  EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i, bi)
     {
       struct version_info *info;
 
@@ -4244,22 +5888,23 @@ free_loop_data (struct ivopts_data *data)
       info->has_nonlin_use = false;
       info->preserve_biv = false;
       info->inv_id = 0;
-    });
+    }
   bitmap_clear (data->relevant);
+  bitmap_clear (data->important_candidates);
 
   for (i = 0; i < n_iv_uses (data); i++)
     {
       struct iv_use *use = iv_use (data, i);
 
       free (use->iv);
-      BITMAP_XFREE (use->related_cands);
+      BITMAP_FREE (use->related_cands);
       for (j = 0; j < use->n_map_members; j++)
        if (use->cost_map[j].depends_on)
-         BITMAP_XFREE (use->cost_map[j].depends_on);
+         BITMAP_FREE (use->cost_map[j].depends_on);
       free (use->cost_map);
       free (use);
     }
-  VARRAY_POP_ALL (data->iv_uses);
+  VEC_truncate (iv_use_p, data->iv_uses, 0);
 
   for (i = 0; i < n_iv_cands (data); i++)
     {
@@ -4267,27 +5912,25 @@ free_loop_data (struct ivopts_data *data)
 
       if (cand->iv)
        free (cand->iv);
+      if (cand->depends_on)
+       BITMAP_FREE (cand->depends_on);
       free (cand);
     }
-  VARRAY_POP_ALL (data->iv_candidates);
+  VEC_truncate (iv_cand_p, data->iv_candidates, 0);
 
   if (data->version_info_size < num_ssa_names)
     {
       data->version_info_size = 2 * num_ssa_names;
       free (data->version_info);
-      data->version_info = xcalloc (data->version_info_size,
-                                   sizeof (struct version_info));
+      data->version_info = XCNEWVEC (struct version_info, data->version_info_size);
     }
 
   data->max_inv_id = 0;
 
-  for (i = 0; i < VARRAY_ACTIVE_SIZE (decl_rtl_to_reset); i++)
-    {
-      tree obj = VARRAY_GENERIC_PTR_NOGC (decl_rtl_to_reset, i);
+  for (i = 0; VEC_iterate (tree, decl_rtl_to_reset, i, obj); i++)
+    SET_DECL_RTL (obj, NULL_RTX);
 
-      SET_DECL_RTL (obj, NULL_RTX);
-    }
-  VARRAY_POP_ALL (decl_rtl_to_reset);
+  VEC_truncate (tree, decl_rtl_to_reset, 0);
 }
 
 /* Finalizes data structures used by the iv optimization pass.  LOOPS is the
@@ -4307,11 +5950,13 @@ tree_ssa_iv_optimize_finalize (struct loops *loops, struct ivopts_data *data)
 
   free_loop_data (data);
   free (data->version_info);
-  BITMAP_XFREE (data->relevant);
+  BITMAP_FREE (data->relevant);
+  BITMAP_FREE (data->important_candidates);
+  htab_delete (data->niters);
 
-  VARRAY_FREE (decl_rtl_to_reset);
-  VARRAY_FREE (data->iv_uses);
-  VARRAY_FREE (data->iv_candidates);
+  VEC_free (tree, heap, decl_rtl_to_reset);
+  VEC_free (iv_use_p, heap, data->iv_uses);
+  VEC_free (iv_cand_p, heap, data->iv_candidates);
 }
 
 /* Optimizes the LOOP.  Returns true if anything changed.  */
@@ -4320,7 +5965,7 @@ static bool
 tree_ssa_iv_optimize_loop (struct ivopts_data *data, struct loop *loop)
 {
   bool changed = false;
-  bitmap iv_set;
+  struct iv_ca *iv_ca;
   edge exit;
 
   data->current_loop = loop;
@@ -4360,13 +6005,14 @@ tree_ssa_iv_optimize_loop (struct ivopts_data *data, struct loop *loop)
   determine_set_costs (data);
 
   /* Find the optimal set of induction variables (item 3, part 2).  */
-  iv_set = find_optimal_iv_set (data);
-  if (!iv_set)
+  iv_ca = find_optimal_iv_set (data);
+  if (!iv_ca)
     goto finish;
   changed = true;
 
   /* Create the new induction variables (item 4, part 1).  */
-  create_new_ivs (data, iv_set);
+  create_new_ivs (data, iv_ca);
+  iv_ca_free (&iv_ca);
   
   /* Rewrite the uses (item 4, part 2).  */
   rewrite_uses (data);
@@ -4374,10 +6020,6 @@ tree_ssa_iv_optimize_loop (struct ivopts_data *data, struct loop *loop)
   /* Remove the ivs that are unused after rewriting.  */
   remove_unused_ivs (data);
 
-  loop_commit_inserts ();
-
-  BITMAP_XFREE (iv_set);
-
   /* We have changed the structure of induction variables; it might happen
      that definitions in the scev database refer to some of them that were
      eliminated.  */
@@ -4404,23 +6046,13 @@ tree_ssa_iv_optimize (struct loops *loops)
   while (loop->inner)
     loop = loop->inner;
 
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-  verify_stmts ();
-#endif
-
   /* Scan the loops, inner ones first.  */
   while (loop != loops->tree_root)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        flow_loop_dump (loop, dump_file, NULL, 1);
-      if (tree_ssa_iv_optimize_loop (&data, loop))
-       {
-#ifdef ENABLE_CHECKING
-         verify_loop_closed_ssa ();
-          verify_stmts ();
-#endif
-       }
+
+      tree_ssa_iv_optimize_loop (&data, loop);
 
       if (loop->next)
        {