re PR tree-optimization/18316 (Missed IV optimization)
authorZdenek Dvorak <dvorakz@suse.cz>
Sun, 1 May 2005 08:08:14 +0000 (10:08 +0200)
committerZdenek Dvorak <rakdver@gcc.gnu.org>
Sun, 1 May 2005 08:08:14 +0000 (08:08 +0000)
PR tree-optimization/18316
PR tree-optimization/19126
* tree.c (build_int_cst_type): Avoid shift by size of type.
* tree-scalar-evolution.c (simple_iv): Add allow_nonconstant_step
argument.
* tree-scalar-evolution.h (simple_iv): Declaration changed.
* tree-ssa-loop-ivopts.c (struct iv_cand): Add depends_on
field.
(dump_cand): Dump depends_on information.
(determine_biv_step): Add argument to simple_iv call.
(contains_abnormal_ssa_name_p): Handle case expr == NULL.
(find_bivs, find_givs_in_stmt_scev): Do not require step to be a
constant.
(add_candidate_1): Record depends_on for candidates.
(tree_int_cst_sign_bit, constant_multiple_of): New functions.
(get_computation_at, get_computation_cost_at, may_eliminate_iv):
Handle ivs with nonconstant step.
(iv_ca_set_remove_invariants, iv_ca_set_add_invariants): New functions.
(iv_ca_set_no_cp, iv_ca_set_cp): Handle cand->depends_on.
(create_new_iv): Unshare the step before passing it to create_iv.
(free_loop_data): Free cand->depends_on.
(build_addr_strip_iref): New function.
(find_interesting_uses_address): Use build_addr_strip_iref.
(strip_offset_1): Split the recursive part from strip_offset.
Strip constant offset component_refs and array_refs.
(strip_offset): Split the recursive part to strip_offset_1.
(add_address_candidates): Removed.
(add_derived_ivs_candidates): Do not use add_address_candidates.
(add_iv_value_candidates): Add candidates with stripped constant
offset.  Consider all candidates with initial value 0 important.
(struct affine_tree_combination): New.
(aff_combination_const, aff_combination_elt, aff_combination_scale,
aff_combination_add_elt, aff_combination_add,
tree_to_aff_combination, add_elt_to_tree, aff_combination_to_tree,
fold_affine_sum): New functions.
(get_computation_at): Use fold_affine_sum.
* tree-ssa-loop-manip.c (create_iv): Handle ivs with nonconstant step.
* tree-ssa-loop-niter.c (number_of_iterations_exit): Add argument
to simple_iv call.

* gcc.dg/tree-ssa/loop-8.c: New test.

From-SVN: r99059

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/loop-8.c [new file with mode: 0644]
gcc/tree-scalar-evolution.c
gcc/tree-scalar-evolution.h
gcc/tree-ssa-loop-ivopts.c
gcc/tree-ssa-loop-manip.c
gcc/tree-ssa-loop-niter.c
gcc/tree.c

index 279d4b1..af36b4e 100644 (file)
@@ -1,3 +1,45 @@
+2005-05-01  Zdenek Dvorak  <dvorakz@suse.cz>
+
+       PR tree-optimization/18316
+       PR tree-optimization/19126
+       * tree.c (build_int_cst_type): Avoid shift by size of type.
+       * tree-scalar-evolution.c (simple_iv): Add allow_nonconstant_step
+       argument.
+       * tree-scalar-evolution.h (simple_iv): Declaration changed.
+       * tree-ssa-loop-ivopts.c (struct iv_cand): Add depends_on
+       field.
+       (dump_cand): Dump depends_on information.
+       (determine_biv_step): Add argument to simple_iv call.
+       (contains_abnormal_ssa_name_p): Handle case expr == NULL.
+       (find_bivs, find_givs_in_stmt_scev): Do not require step to be a
+       constant.
+       (add_candidate_1): Record depends_on for candidates.
+       (tree_int_cst_sign_bit, constant_multiple_of): New functions.
+       (get_computation_at, get_computation_cost_at, may_eliminate_iv):
+       Handle ivs with nonconstant step.
+       (iv_ca_set_remove_invariants, iv_ca_set_add_invariants): New functions.
+       (iv_ca_set_no_cp, iv_ca_set_cp): Handle cand->depends_on.
+       (create_new_iv): Unshare the step before passing it to create_iv.
+       (free_loop_data): Free cand->depends_on.
+       (build_addr_strip_iref): New function.
+       (find_interesting_uses_address): Use build_addr_strip_iref.
+       (strip_offset_1): Split the recursive part from strip_offset.
+       Strip constant offset component_refs and array_refs.
+       (strip_offset): Split the recursive part to strip_offset_1.
+       (add_address_candidates): Removed.
+       (add_derived_ivs_candidates): Do not use add_address_candidates.
+       (add_iv_value_candidates): Add candidates with stripped constant
+       offset.  Consider all candidates with initial value 0 important.
+       (struct affine_tree_combination): New.
+       (aff_combination_const, aff_combination_elt, aff_combination_scale,
+       aff_combination_add_elt, aff_combination_add,
+       tree_to_aff_combination, add_elt_to_tree, aff_combination_to_tree,
+       fold_affine_sum): New functions.
+       (get_computation_at): Use fold_affine_sum.
+       * tree-ssa-loop-manip.c (create_iv): Handle ivs with nonconstant step.
+       * tree-ssa-loop-niter.c (number_of_iterations_exit): Add argument
+       to simple_iv call.
+
 2005-04-30  Michael Matz  <matz@suse.de>
 
        * config/i386/i386.md (movmemsi): Also active when
index d212e86..f1c04ec 100644 (file)
@@ -1,3 +1,7 @@
+2005-05-01  Zdenek Dvorak  <dvorakz@suse.cz>
+
+       * gcc.dg/tree-ssa/loop-8.c: New test.
+
 2005-04-30  Michael Maty  <matz@suse.de>
 
        * gcc.dg/inline-mcpy.c: New test.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-8.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-8.c
new file mode 100644 (file)
index 0000000..9718aad
--- /dev/null
@@ -0,0 +1,25 @@
+/* A test for strength reduction of ivs with nonconstant step.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-vars" } */
+
+int bar (void);
+
+int a[100];
+
+void xxx (void)
+{
+  int iter, step = bar ();
+
+  for (iter = 0; iter < 10; iter++)
+    a[iter * step] = bar ();
+}
+
+/* The array access should be strength reduced.  But to determine the value of
+   the step, we need to calculate step * sizeof (int), thus we need to be
+   a bit careful about which multiplications we disallow.  */
+
+/* { dg-final { scan-tree-dump-times "step \\* \[^0-9\]" 0 "vars" } } */
+/* { dg-final { scan-tree-dump-times "\[^0-9\] \\* step" 0 "vars" } } */
+
+/* { dg-final { cleanup-tree-dump "vars" } } */
index ca80893..c923409 100644 (file)
@@ -2547,10 +2547,13 @@ scev_reset (void)
 }
 
 /* Checks whether OP behaves as a simple affine iv of LOOP in STMT and returns
-   its BASE and STEP if possible.  */
+   its BASE and STEP if possible.  If ALLOW_NONCONSTANT_STEP is true, we
+   want STEP to be invariant in LOOP.  Otherwise we require it to be an
+   integer constant.  */
 
 bool
-simple_iv (struct loop *loop, tree stmt, tree op, tree *base, tree *step)
+simple_iv (struct loop *loop, tree stmt, tree op, tree *base, tree *step,
+          bool allow_nonconstant_step)
 {
   basic_block bb = bb_for_stmt (stmt);
   tree type, ev;
@@ -2579,8 +2582,15 @@ simple_iv (struct loop *loop, tree stmt, tree op, tree *base, tree *step)
     return false;
 
   *step = CHREC_RIGHT (ev);
-  if (TREE_CODE (*step) != INTEGER_CST)
+  if (allow_nonconstant_step)
+    {
+      if (tree_contains_chrecs (*step, NULL)
+         || chrec_contains_symbols_defined_in_loop (*step, loop->num))
+       return false;
+    }
+  else if (TREE_CODE (*step) != INTEGER_CST)
     return false;
+
   *base = CHREC_LEFT (ev);
   if (tree_contains_chrecs (*base, NULL)
       || chrec_contains_symbols_defined_in_loop (*base, loop->num))
index caefa3b..def30b4 100644 (file)
@@ -32,6 +32,6 @@ extern tree analyze_scalar_evolution (struct loop *, tree);
 extern tree instantiate_parameters (struct loop *, tree);
 extern void gather_stats_on_scev_database (void);
 extern void scev_analysis (void);
-extern bool simple_iv (struct loop *, tree, tree, tree *, tree *);
+extern bool simple_iv (struct loop *, tree, tree, tree *, tree *, bool);
 
 #endif  /* GCC_TREE_SCALAR_EVOLUTION_H  */
index f7373a4..1d8e308 100644 (file)
@@ -191,6 +191,8 @@ 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.  */
@@ -492,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");
@@ -864,23 +872,23 @@ 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);
 
   if (!is_gimple_reg (name))
     return NULL_TREE;
 
-  if (!simple_iv (loop, phi, name, &base, &step))
+  if (!simple_iv (loop, phi, name, &base, &step, true))
     return NULL_TREE;
 
-  if (!step)
-    return build_int_cst (type, 0);
+  if (zero_p (step))
+    return NULL_TREE;
 
   return step;
 }
@@ -923,9 +931,15 @@ idx_contains_abnormal_ssa_name_p (tree base, tree *index,
 static bool
 contains_abnormal_ssa_name_p (tree expr)
 {
-  enum tree_code code = TREE_CODE (expr);
-  enum tree_code_class 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;
 
@@ -974,25 +988,18 @@ find_bivs (struct ivopts_data *data)
        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))
+      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;
@@ -1053,16 +1060,11 @@ 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))
+  if (!simple_iv (loop, stmt, TREE_OPERAND (stmt, 1), base, step, true))
     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))
-    return false;
-
-  if (contains_abnormal_ssa_name_p (*base))
+  if (contains_abnormal_ssa_name_p (*base)
+      || contains_abnormal_ssa_name_p (*step))
     return false;
 
   return true;
@@ -1451,13 +1453,12 @@ idx_find_step (tree base, tree *idx, void *data)
       return false;
     }
 
-  step = fold_binary_to_constant (MULT_EXPR, type, step, iv_step);
+  step = fold_build2 (MULT_EXPR, type, step, iv_step);
 
   if (!*dta->step_p)
     *dta->step_p = step;
   else
-    *dta->step_p = fold_binary_to_constant (PLUS_EXPR, type,
-                                           *dta->step_p, step);
+    *dta->step_p = fold_build2 (PLUS_EXPR, type, *dta->step_p, step);
 
   return true;
 }
@@ -1509,6 +1510,25 @@ may_be_unaligned_p (tree ref)
   return false;
 }
 
+/* Builds ADDR_EXPR of object OBJ.  If OBJ is an INDIRECT_REF, the indirect_ref
+   is stripped instead.  */
+
+static tree
+build_addr_strip_iref (tree obj)
+{
+  tree type;
+
+  if (TREE_CODE (obj) == INDIRECT_REF)
+    {
+      type = build_pointer_type (TREE_TYPE (obj));
+      obj = fold_convert (type, TREE_OPERAND (obj, 0));
+    }
+  else
+    obj = build_addr (obj);
+
+  return obj;
+}
+
 /* Finds addresses in *OP_P inside STMT.  */
 
 static void
@@ -1543,10 +1563,7 @@ find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
   gcc_assert (TREE_CODE (base) != ALIGN_INDIRECT_REF);
   gcc_assert (TREE_CODE (base) != MISALIGNED_INDIRECT_REF);
 
-  if (TREE_CODE (base) == INDIRECT_REF)
-    base = TREE_OPERAND (base, 0);
-  else
-    base = build_addr (base);
+  base = build_addr_strip_iref (base);
 
   civ = alloc_iv (base, step);
   record_use (data, op_p, civ, stmt, USE_ADDRESS);
@@ -1758,18 +1775,21 @@ find_interesting_uses (struct ivopts_data *data)
 }
 
 /* Strips constant offsets from EXPR and stores them to OFFSET.  If INSIDE_ADDR
-   is true, assume we are inside an address.  */
+   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 tree
-strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
+strip_offset_1 (tree expr, bool inside_addr, bool top_compref,
+               unsigned HOST_WIDE_INT *offset)
 {
-  tree op0 = NULL_TREE, op1 = NULL_TREE, step;
+  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;
@@ -1789,8 +1809,8 @@ strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
       op0 = TREE_OPERAND (expr, 0);
       op1 = TREE_OPERAND (expr, 1);
 
-      op0 = strip_offset (op0, false, &off0);
-      op1 = strip_offset (op1, false, &off1);
+      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)
@@ -1804,10 +1824,10 @@ strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
          if (code == PLUS_EXPR)
            expr = op1;
          else
-           expr = build1 (NEGATE_EXPR, type, op1);
+           expr = fold_build1 (NEGATE_EXPR, type, op1);
        }
       else
-       expr = build2 (code, type, op0, op1);
+       expr = fold_build2 (code, type, op0, op1);
 
       return fold_convert (orig_type, expr);
 
@@ -1821,17 +1841,49 @@ strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
 
       st = int_cst_value (step);
       op1 = TREE_OPERAND (expr, 1);
-      op1 = strip_offset (op1, false, &off1);
+      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:
-      inside_addr = true;
+      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_addr_strip_iref (op0);
+      return fold_convert (orig_type, expr);
+
+    case INDIRECT_REF:
+      inside_addr = false;
       break;
 
     default:
@@ -1841,7 +1893,7 @@ strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
   /* Default handling of expressions for that we want to recurse into
      the first operand.  */
   op0 = TREE_OPERAND (expr, 0);
-  op0 = strip_offset (op0, inside_addr, &off0);
+  op0 = strip_offset_1 (op0, inside_addr, false, &off0);
   *offset += off0;
 
   if (op0 == TREE_OPERAND (expr, 0)
@@ -1853,7 +1905,20 @@ strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
   if (op1)
     TREE_OPERAND (expr, 1) = op1;
 
-  return fold_convert (orig_type, expr);
+  /* Inside address, we might strip the top level component references,
+     thus changing type of the expresion.  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.
@@ -1872,6 +1937,30 @@ generic_type_for (tree 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
@@ -1954,6 +2043,13 @@ add_candidate_1 (struct ivopts_data *data,
       cand->incremented_at = incremented_at;
       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);
     }
@@ -2089,50 +2185,19 @@ static void
 add_iv_value_candidates (struct ivopts_data *data,
                         struct iv *iv, struct iv_use *use)
 {
-  add_candidate (data, iv->base, iv->step, false, use);
-
-  /* The same, but with initial value zero.  */
-  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;
   unsigned HOST_WIDE_INT offset;
+  tree base;
 
-  /* 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))
-       { 
-         gcc_assert (TREE_CODE (base) != ALIGN_INDIRECT_REF);
-         gcc_assert (TREE_CODE (base) != MISALIGNED_INDIRECT_REF);
+  add_candidate (data, iv->base, iv->step, false, use);
 
-         if (TREE_CODE (base) == INDIRECT_REF)
-           base = TREE_OPERAND (base, 0);
-         else
-           base = build_addr (base);
-         add_candidate (data, base, iv->step, false, use);
-       }
-    }
+  /* 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, true, use);
 
   /* Third, try removing the constant offset.  */
-  abase = iv->base;
-  base = strip_offset (abase, false, &offset);
+  base = strip_offset (iv->base, &offset);
   if (offset)
     add_candidate (data, base, iv->step, false, use);
 }
@@ -2172,6 +2237,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;
@@ -2184,10 +2250,6 @@ 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:
          gcc_unreachable ();
        }
@@ -2494,6 +2556,452 @@ var_at_stmt (struct loop *loop, struct iv_cand *cand, tree stmt)
     return cand->var_before;
 }
 
+/* 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 int
+tree_int_cst_sign_bit (tree t)
+{
+  unsigned bitno = TYPE_PRECISION (TREE_TYPE (t)) - 1;
+  unsigned HOST_WIDE_INT w;
+
+  if (bitno < HOST_BITS_PER_WIDE_INT)
+    w = TREE_INT_CST_LOW (t);
+  else
+    {
+      w = TREE_INT_CST_HIGH (t);
+      bitno -= HOST_BITS_PER_WIDE_INT;
+    }
+
+  return (w >> bitno) & 1;
+}
+
+/* If we can prove that TOP = cst * BOT for some constant cst in TYPE,
+   return cst.  Otherwise return NULL_TREE.  */
+
+static tree
+constant_multiple_of (tree type, tree top, tree bot)
+{
+  tree res, mby, p0, p1;
+  enum tree_code code;
+  bool negate;
+
+  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)
+    {
+    case MULT_EXPR:
+      mby = TREE_OPERAND (top, 1);
+      if (TREE_CODE (mby) != INTEGER_CST)
+       return NULL_TREE;
+
+      res = constant_multiple_of (type, TREE_OPERAND (top, 0), bot);
+      if (!res)
+       return NULL_TREE;
+
+      return fold_binary_to_constant (MULT_EXPR, type, res,
+                                     fold_convert (type, mby));
+
+    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;
+
+      return fold_binary_to_constant (code, type, p0, p1);
+
+    case INTEGER_CST:
+      if (TREE_CODE (bot) != INTEGER_CST)
+       return NULL_TREE;
+
+      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;
+    }
+}
+
+/* Affine combination of trees.  We keep track of at most MAX_AFF_ELTS elements
+   to make things simpler; this is sufficient in most cases.  */
+
+#define MAX_AFF_ELTS 8
+
+struct affine_tree_combination
+{
+  /* Type of the result of the combination.  */
+  tree type;
+
+  /* Mask modulo that the operations are performed.  */
+  unsigned HOST_WIDE_INT mask;
+
+  /* Constant offset.  */
+  unsigned HOST_WIDE_INT offset;
+
+  /* Number of elements of the combination.  */
+  unsigned n;
+
+  /* Elements and their coefficients.  */
+  tree elts[MAX_AFF_ELTS];
+  unsigned HOST_WIDE_INT coefs[MAX_AFF_ELTS];
+
+  /* Remainder of the expression.  */
+  tree rest;
+};
+
+/* 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)
+    {
+      aff_combination_const (comb, comb->type, 0);
+      return;
+    }
+
+  comb->offset = (scale * comb->offset) & comb->mask;
+  for (i = 0, j = 0; i < comb->n; i++)
+    {
+      comb->coefs[j] = (scale * comb->coefs[i]) & comb->mask;
+      comb->elts[j] = comb->elts[i];
+      if (comb->coefs[j] != 0)
+       j++;
+    }
+  comb->n = j;
+
+  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));
+    }
+}
+
+/* Adds ELT * SCALE to COMB.  */
+
+static void
+aff_combination_add_elt (struct affine_tree_combination *comb, tree elt,
+                        unsigned HOST_WIDE_INT scale)
+{
+  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];
+       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;
+}
+
+/* Adds COMB2 to COMB1.  */
+
+static void
+aff_combination_add (struct affine_tree_combination *comb1,
+                    struct affine_tree_combination *comb2)
+{
+  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;
+  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)
+    {
+    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_addr_strip_iref (core);
+      if (TREE_CODE (core) == ADDR_EXPR)
+       aff_combination_add_elt (comb, core, 1);
+      else
+       {
+         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;
+
+    default:
+      break;
+    }
+
+  aff_combination_elt (comb, type, expr);
+}
+
+/* Creates EXPR + ELT * SCALE in TYPE.  MASK is the mask for width of TYPE.  */
+
+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);
+}
+
+/* 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;
+
+  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);
+}
+
+/* Folds X + RATIO * Y in TYPE.  */
+
+static tree
+fold_affine_sum (tree type, tree x, tree y, HOST_WIDE_INT ratio)
+{
+  enum tree_code code;
+  tree cst;
+  struct affine_tree_combination cx, cy;
+
+  if (TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT)
+    {
+      if (ratio == 1)
+       return fold_build2 (PLUS_EXPR, type, x, y);
+      if (ratio == -1)
+       return fold_build2 (MINUS_EXPR, type, x, y);
+
+      if (ratio < 0)
+       {
+         code = MINUS_EXPR;
+         ratio = -ratio;
+       }
+      else
+       code = PLUS_EXPR;
+
+      cst = build_int_cst_type (type, ratio);
+      y = fold_build2 (MULT_EXPR, type, y, cst);
+      return fold_build2 (code, type, x, y);
+    }
+
+  tree_to_aff_combination (x, type, &cx);
+  tree_to_aff_combination (y, type, &cy);
+  aff_combination_scale (&cy, ratio);
+  aff_combination_add (&cx, &cy);
+
+  return aff_combination_to_tree (&cx);
+}
+
 /* Determines the expression by that USE is expressed from induction variable
    CAND at statement AT in LOOP.  */
 
@@ -2542,19 +3050,41 @@ get_computation_at (struct loop *loop,
       cstep = fold_convert (uutype, cstep);
     }
 
-  if (!cst_and_fits_in_hwi (cstep)
-      || !cst_and_fits_in_hwi (ustep))
-    return NULL_TREE;
+  if (cst_and_fits_in_hwi (cstep)
+      && cst_and_fits_in_hwi (ustep))
+    {
+      ustepi = int_cst_value (ustep);
+      cstepi = int_cst_value (cstep);
 
-  ustepi = int_cst_value (ustep);
-  cstepi = int_cst_value (cstep);
+      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;
+       }
 
-  if (!divide (TYPE_PRECISION (uutype), ustepi, cstepi, &ratioi))
+      ratio = build_int_cst_type (uutype, ratioi);
+    }
+  else
     {
-      /* 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;
+      ratio = constant_multiple_of (uutype, ustep, cstep);
+      if (!ratio)
+       return NULL_TREE;
+
+      /* 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.  */
@@ -2571,21 +3101,25 @@ get_computation_at (struct loop *loop,
 
   if (ratioi == 1)
     {
-      delta = fold (build2 (MINUS_EXPR, uutype, ubase, cbase));
-      expr = fold (build2 (PLUS_EXPR, uutype, expr, delta));
+      delta = fold_affine_sum (uutype, ubase, cbase, -1);
+      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));
+      delta = fold_affine_sum (uutype, ubase, cbase, 1);
+      expr = fold_build2 (MINUS_EXPR, uutype, delta, expr);
     }
   else
     {
-      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));
+      if (ratioi)
+       delta = fold_affine_sum (uutype, ubase, cbase, -ratioi);
+      else
+       {
+         delta = fold_build2 (MULT_EXPR, uutype, ratio, cbase);
+         delta = fold_affine_sum (uutype, ubase, delta, -1);
+       }
+      expr = fold_build2 (MULT_EXPR, uutype, ratio, expr);
+      expr = fold_build2 (PLUS_EXPR, uutype, delta, expr);
     }
 
   return fold_convert (utype, expr);
@@ -2849,31 +3383,6 @@ 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_ALLOC (NULL);
-  bitmap_set_bit (*depends_on, info->inv_id);
-
-  return NULL_TREE;
-}
-
 /* Estimates cost of forcing EXPR into a variable.  DEPENDS_ON is a set of the
    invariants the computation depends on.  */
 
@@ -3107,8 +3616,8 @@ difference_cost (struct ivopts_data *data,
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (e1));
   unsigned HOST_WIDE_INT off1, off2;
 
-  e1 = strip_offset (e1, false, &off1);
-  e2 = strip_offset (e2, false, &off2);
+  e1 = strip_offset (e1, &off1);
+  e2 = strip_offset (e2, &off2);
   *offset += off1 - off2;
 
   STRIP_NOPS (e1);
@@ -3191,29 +3700,49 @@ 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 (TYPE_PRECISION (utype) != TYPE_PRECISION (ctype))
     {
       /* TODO -- add direct handling of this case.  */
       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 inprecise (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
@@ -3222,7 +3751,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,
@@ -3432,6 +3961,9 @@ may_eliminate_iv (struct ivopts_data *data,
   tree wider_type, period, per_type;
   struct loop *loop = data->current_loop;
   
+  if (TREE_CODE (cand->iv->step) != INTEGER_CST)
+    return false;
+
   /* 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);
@@ -3905,16 +4437,33 @@ iv_ca_recount_cost (struct ivopts_data *data, struct iv_ca *ivs)
   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, iid;
-  bitmap deps;
+  unsigned uid = use->id, cid;
   struct cost_pair *cp;
-  bitmap_iterator bi;
 
   cp = ivs->cand_for_use[uid];
   if (!cp)
@@ -3933,23 +4482,33 @@ iv_ca_set_no_cp (struct ivopts_data *data, struct iv_ca *ivs,
        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;
 
-  deps = cp->depends_on;
+  iv_ca_set_remove_invariants (ivs, cp->depends_on);
+  iv_ca_recount_cost (data, ivs);
+}
+
+/* Add invariants in set INVS to set IVS.  */
 
-  if (deps)
+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)
     {
-      EXECUTE_IF_SET_IN_BITMAP (deps, 0, iid, bi)
-       {
-         ivs->n_invariant_uses[iid]--;
-         if (ivs->n_invariant_uses[iid] == 0)
-           ivs->n_regs--;
-       }
+      ivs->n_invariant_uses[iid]++;
+      if (ivs->n_invariant_uses[iid] == 1)
+       ivs->n_regs++;
     }
-
-  iv_ca_recount_cost (data, ivs);
 }
 
 /* Set cost pair for USE in set IVS to CP.  */
@@ -3958,9 +4517,7 @@ 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, iid;
-  bitmap deps;
-  bitmap_iterator bi;
+  unsigned uid = use->id, cid;
 
   if (ivs->cand_for_use[uid] == cp)
     return;
@@ -3983,22 +4540,12 @@ iv_ca_set_cp (struct ivopts_data *data, struct iv_ca *ivs,
            ivs->n_regs++;
          ivs->n_cands++;
          ivs->cand_cost += cp->cand->cost;
-       }
-
-      ivs->cand_use_cost += cp->cost;
-
-      deps = cp->depends_on;
 
-      if (deps)
-       {
-         EXECUTE_IF_SET_IN_BITMAP (deps, 0, iid, bi)
-           {
-             ivs->n_invariant_uses[iid]++;
-             if (ivs->n_invariant_uses[iid] == 1)
-               ivs->n_regs++;
-           }
+         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);
     }
 }
@@ -4681,7 +5228,8 @@ 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);
 }
 
@@ -5287,6 +5835,8 @@ free_loop_data (struct ivopts_data *data)
 
       if (cand->iv)
        free (cand->iv);
+      if (cand->depends_on)
+       BITMAP_FREE (cand->depends_on);
       free (cand);
     }
   VEC_truncate (iv_cand_p, data->iv_candidates, 0);
index f16ec3f..ff8f899 100644 (file)
@@ -54,6 +54,7 @@ create_iv (tree base, tree step, tree var, struct loop *loop,
   tree stmt, initial, step1, stmts;
   tree vb, va;
   enum tree_code incr_op = PLUS_EXPR;
+  edge pe = loop_preheader_edge (loop);
 
   if (!var)
     {
@@ -92,6 +93,12 @@ create_iv (tree base, tree step, tree var, struct loop *loop,
        }
     }
 
+  /* Gimplify the step if necessary.  We put the computations in front of the
+     loop (i.e. the step should be loop invariant).  */
+  step = force_gimple_operand (step, &stmts, true, var);
+  if (stmts)
+    bsi_insert_on_edge_immediate_loop (pe, stmts);
+
   stmt = build2 (MODIFY_EXPR, void_type_node, va,
                 build2 (incr_op, TREE_TYPE (base),
                         vb, step));
@@ -103,11 +110,7 @@ create_iv (tree base, tree step, tree var, struct loop *loop,
 
   initial = force_gimple_operand (base, &stmts, true, var);
   if (stmts)
-    {
-      edge pe = loop_preheader_edge (loop);
-
-      bsi_insert_on_edge_immediate_loop (pe, stmts);
-    }
+    bsi_insert_on_edge_immediate_loop (pe, stmts);
 
   stmt = create_phi_node (vb, loop->header);
   SSA_NAME_DEF_STMT (vb) = stmt;
index ab9de0b..5d01487 100644 (file)
@@ -952,9 +952,9 @@ number_of_iterations_exit (struct loop *loop, edge exit,
       && !POINTER_TYPE_P (type))
     return false;
      
-  if (!simple_iv (loop, stmt, op0, &base0, &step0))
+  if (!simple_iv (loop, stmt, op0, &base0, &step0, false))
     return false;
-  if (!simple_iv (loop, stmt, op1, &base1, &step1))
+  if (!simple_iv (loop, stmt, op1, &base1, &step1, false))
     return false;
 
   niter->niter = NULL_TREE;
index 21e681c..48efe09 100644 (file)
@@ -518,7 +518,7 @@ tree
 build_int_cst_type (tree type, HOST_WIDE_INT low)
 {
   unsigned HOST_WIDE_INT val = (unsigned HOST_WIDE_INT) low;
-  unsigned HOST_WIDE_INT hi;
+  unsigned HOST_WIDE_INT hi, mask;
   unsigned bits;
   bool signed_p;
   bool negative;
@@ -538,10 +538,12 @@ build_int_cst_type (tree type, HOST_WIDE_INT low)
       negative = ((val >> (bits - 1)) & 1) != 0;
 
       /* Mask out the bits outside of the precision of the constant.  */
+      mask = (((unsigned HOST_WIDE_INT) 2) << (bits - 1)) - 1;
+
       if (signed_p && negative)
-       val = val | ((~(unsigned HOST_WIDE_INT) 0) << bits);
+       val |= ~mask;
       else
-       val = val & ~((~(unsigned HOST_WIDE_INT) 0) << bits);
+       val &= mask;
     }
 
   /* Determine the high bits.  */
@@ -556,7 +558,8 @@ build_int_cst_type (tree type, HOST_WIDE_INT low)
       else
        {
          bits -= HOST_BITS_PER_WIDE_INT;
-         hi = hi & ~((~(unsigned HOST_WIDE_INT) 0) << bits);
+         mask = (((unsigned HOST_WIDE_INT) 2) << (bits - 1)) - 1;
+         hi &= mask;
        }
     }