OSDN Git Service

2008-08-18 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-loop-ivopts.c
index ef7d64a..1a1e58b 100644 (file)
@@ -1,5 +1,6 @@
 /* Induction variable optimizations.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software
+   Foundation, Inc.
    
 This file is part of GCC.
    
@@ -162,7 +163,7 @@ struct iv_use
   unsigned id;         /* The id of the use.  */
   enum use_type type;  /* Type of the use.  */
   struct iv *iv;       /* The induction variable it is based on.  */
-  tree stmt;           /* Statement in that it occurs.  */
+  gimple stmt;         /* Statement in that it occurs.  */
   tree *op_p;          /* The place where it occurs.  */
   bitmap related_cands;        /* The set of "related" iv candidates, plus the common
                           important ones.  */
@@ -190,7 +191,7 @@ struct iv_cand
   bool important;      /* Whether this is an "important" candidate, i.e. such
                           that it should be considered by all uses.  */
   enum iv_position pos;        /* Where it is computed.  */
-  tree incremented_at; /* For original biv, the statement where it is
+  gimple incremented_at;/* For original biv, the statement where it is
                           incremented.  */
   tree var_before;     /* The variable used for it before increment.  */
   tree var_after;      /* The variable used for it after increment.  */
@@ -447,7 +448,7 @@ dump_use (FILE *file, struct iv_use *use)
     }
 
   fprintf (file, "  in statement ");
-  print_generic_expr (file, use->stmt, TDF_SLIM);
+  print_gimple_stmt (file, use->stmt, 0, 0);
   fprintf (file, "\n");
 
   fprintf (file, "  at position ");
@@ -543,9 +544,9 @@ name_info (struct ivopts_data *data, tree name)
    emitted in LOOP.  */
 
 static bool
-stmt_after_ip_normal_pos (struct loop *loop, tree stmt)
+stmt_after_ip_normal_pos (struct loop *loop, gimple stmt)
 {
-  basic_block bb = ip_normal_pos (loop), sbb = bb_for_stmt (stmt);
+  basic_block bb = ip_normal_pos (loop), sbb = gimple_bb (stmt);
 
   gcc_assert (bb);
 
@@ -562,11 +563,11 @@ stmt_after_ip_normal_pos (struct loop *loop, tree stmt)
    variable CAND is incremented.  */
 
 static bool
-stmt_after_ip_original_pos (struct iv_cand *cand, tree stmt)
+stmt_after_ip_original_pos (struct iv_cand *cand, gimple stmt)
 {
-  basic_block cand_bb = bb_for_stmt (cand->incremented_at);
-  basic_block stmt_bb = bb_for_stmt (stmt);
-  block_stmt_iterator bsi;
+  basic_block cand_bb = gimple_bb (cand->incremented_at);
+  basic_block stmt_bb = gimple_bb (stmt);
+  gimple_stmt_iterator bsi;
 
   if (!dominated_by_p (CDI_DOMINATORS, stmt_bb, cand_bb))
     return false;
@@ -576,11 +577,11 @@ stmt_after_ip_original_pos (struct iv_cand *cand, tree stmt)
 
   /* Scan the block from the end, since the original ivs are usually
      incremented at the end of the loop body.  */
-  for (bsi = bsi_last (stmt_bb); ; bsi_prev (&bsi))
+  for (bsi = gsi_last_bb (stmt_bb); ; gsi_prev (&bsi))
     {
-      if (bsi_stmt (bsi) == cand->incremented_at)
+      if (gsi_stmt (bsi) == cand->incremented_at)
        return false;
-      if (bsi_stmt (bsi) == stmt)
+      if (gsi_stmt (bsi) == stmt)
        return true;
     }
 }
@@ -589,7 +590,7 @@ stmt_after_ip_original_pos (struct iv_cand *cand, tree stmt)
    CAND is incremented in LOOP.  */
 
 static bool
-stmt_after_increment (struct loop *loop, struct iv_cand *cand, tree stmt)
+stmt_after_increment (struct loop *loop, struct iv_cand *cand, gimple stmt)
 {
   switch (cand->pos)
     {
@@ -772,8 +773,7 @@ determine_base_object (tree expr)
   /* If this is a pointer casted to any type, we need to determine
      the base object for the pointer; so handle conversions before
      throwing away non-pointer expressions.  */
-  if (TREE_CODE (expr) == NOP_EXPR
-      || TREE_CODE (expr) == CONVERT_EXPR)
+  if (CONVERT_EXPR_P (expr))
     return determine_base_object (TREE_OPERAND (expr, 0));
 
   if (!POINTER_TYPE_P (TREE_TYPE (expr)))
@@ -858,7 +858,7 @@ get_iv (struct ivopts_data *data, tree var)
 
   if (!name_info (data, var)->iv)
     {
-      bb = bb_for_stmt (SSA_NAME_DEF_STMT (var));
+      bb = gimple_bb (SSA_NAME_DEF_STMT (var));
 
       if (!bb
          || !flow_bb_inside_loop_p (data->current_loop, bb))
@@ -872,9 +872,9 @@ get_iv (struct ivopts_data *data, tree var)
    not define a simple affine biv with nonzero step.  */
 
 static tree
-determine_biv_step (tree phi)
+determine_biv_step (gimple phi)
 {
-  struct loop *loop = bb_for_stmt (phi)->loop_father;
+  struct loop *loop = gimple_bb (phi)->loop_father;
   tree name = PHI_RESULT (phi);
   affine_iv iv;
 
@@ -892,12 +892,16 @@ determine_biv_step (tree phi)
 static bool
 find_bivs (struct ivopts_data *data)
 {
-  tree phi, step, type, base;
+  gimple phi;
+  tree step, type, base;
   bool found = false;
   struct loop *loop = data->current_loop;
+  gimple_stmt_iterator psi;
 
-  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
+  for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
     {
+      phi = gsi_stmt (psi);
+
       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)))
        continue;
 
@@ -914,7 +918,12 @@ find_bivs (struct ivopts_data *data)
       type = TREE_TYPE (PHI_RESULT (phi));
       base = fold_convert (type, base);
       if (step)
-       step = fold_convert (type, step);
+       {
+         if (POINTER_TYPE_P (type))
+           step = fold_convert (sizetype, step);
+         else
+           step = fold_convert (type, step);
+       }
 
       set_iv (data, PHI_RESULT (phi), base, step);
       found = true;
@@ -928,13 +937,17 @@ find_bivs (struct ivopts_data *data)
 static void
 mark_bivs (struct ivopts_data *data)
 {
-  tree phi, var;
+  gimple phi;
+  tree var;
   struct iv *iv, *incr_iv;
   struct loop *loop = data->current_loop;
   basic_block incr_bb;
+  gimple_stmt_iterator psi;
 
-  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
+  for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
     {
+      phi = gsi_stmt (psi);
+
       iv = get_iv (data, PHI_RESULT (phi));
       if (!iv)
        continue;
@@ -945,7 +958,7 @@ mark_bivs (struct ivopts_data *data)
        continue;
 
       /* If the increment is in the subloop, ignore it.  */
-      incr_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var));
+      incr_bb = gimple_bb (SSA_NAME_DEF_STMT (var));
       if (incr_bb->loop_father != data->current_loop
          || (incr_bb->flags & BB_IRREDUCIBLE_LOOP))
        continue;
@@ -959,7 +972,7 @@ mark_bivs (struct ivopts_data *data)
    parameters to IV.  */
 
 static bool
-find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, affine_iv *iv)
+find_givs_in_stmt_scev (struct ivopts_data *data, gimple stmt, affine_iv *iv)
 {
   tree lhs;
   struct loop *loop = data->current_loop;
@@ -967,14 +980,14 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, affine_iv *iv)
   iv->base = NULL_TREE;
   iv->step = NULL_TREE;
 
-  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
     return false;
 
-  lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+  lhs = gimple_assign_lhs (stmt);
   if (TREE_CODE (lhs) != SSA_NAME)
     return false;
 
-  if (!simple_iv (loop, stmt, GIMPLE_STMT_OPERAND (stmt, 1), iv, true))
+  if (!simple_iv (loop, stmt, lhs, iv, true))
     return false;
   iv->base = expand_simple_operations (iv->base);
 
@@ -988,14 +1001,14 @@ find_givs_in_stmt_scev (struct ivopts_data *data, tree stmt, affine_iv *iv)
 /* Finds general ivs in statement STMT.  */
 
 static void
-find_givs_in_stmt (struct ivopts_data *data, tree stmt)
+find_givs_in_stmt (struct ivopts_data *data, gimple stmt)
 {
   affine_iv iv;
 
   if (!find_givs_in_stmt_scev (data, stmt, &iv))
     return;
 
-  set_iv (data, GIMPLE_STMT_OPERAND (stmt, 0), iv.base, iv.step);
+  set_iv (data, gimple_assign_lhs (stmt), iv.base, iv.step);
 }
 
 /* Finds general ivs in basic block BB.  */
@@ -1003,10 +1016,10 @@ find_givs_in_stmt (struct ivopts_data *data, tree stmt)
 static void
 find_givs_in_bb (struct ivopts_data *data, basic_block bb)
 {
-  block_stmt_iterator bsi;
+  gimple_stmt_iterator bsi;
 
-  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-    find_givs_in_stmt (data, bsi_stmt (bsi));
+  for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+    find_givs_in_stmt (data, gsi_stmt (bsi));
 }
 
 /* Finds general ivs.  */
@@ -1065,7 +1078,7 @@ find_induction_variables (struct ivopts_data *data)
 
 static struct iv_use *
 record_use (struct ivopts_data *data, tree *use_p, struct iv *iv,
-           tree stmt, enum use_type use_type)
+           gimple stmt, enum use_type use_type)
 {
   struct iv_use *use = XCNEW (struct iv_use);
 
@@ -1102,7 +1115,7 @@ record_invariant (struct ivopts_data *data, tree op, bool nonlinear_use)
       || !is_gimple_reg (op))
     return;
 
-  bb = bb_for_stmt (SSA_NAME_DEF_STMT (op));
+  bb = gimple_bb (SSA_NAME_DEF_STMT (op));
   if (bb
       && flow_bb_inside_loop_p (data->current_loop, bb))
     return;
@@ -1122,7 +1135,7 @@ find_interesting_uses_op (struct ivopts_data *data, tree op)
 {
   struct iv *iv;
   struct iv *civ;
-  tree stmt;
+  gimple stmt;
   struct iv_use *use;
 
   if (TREE_CODE (op) != SSA_NAME)
@@ -1151,8 +1164,8 @@ find_interesting_uses_op (struct ivopts_data *data, tree op)
   *civ = *iv;
 
   stmt = SSA_NAME_DEF_STMT (op);
-  gcc_assert (TREE_CODE (stmt) == PHI_NODE
-             || TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
+  gcc_assert (gimple_code (stmt) == GIMPLE_PHI
+             || is_gimple_assign (stmt));
 
   use = record_use (data, NULL, civ, stmt, USE_NONLINEAR_EXPR);
   iv->use_id = use->id;
@@ -1160,47 +1173,40 @@ find_interesting_uses_op (struct ivopts_data *data, tree op)
   return use;
 }
 
-/* Given a condition *COND_P, checks whether it is a compare of an induction
-   variable and an invariant.  If this is the case, CONTROL_VAR is set
-   to location of the iv, BOUND to the location of the invariant,
-   IV_VAR and IV_BOUND are set to the corresponding induction variable
-   descriptions, and true is returned.  If this is not the case,
-   CONTROL_VAR and BOUND are set to the arguments of the condition and
-   false is returned.  */
+/* Given a condition in statement STMT, checks whether it is a compare
+   of an induction variable and an invariant.  If this is the case,
+   CONTROL_VAR is set to location of the iv, BOUND to the location of
+   the invariant, IV_VAR and IV_BOUND are set to the corresponding
+   induction variable descriptions, and true is returned.  If this is not
+   the case, CONTROL_VAR and BOUND are set to the arguments of the
+   condition and false is returned.  */
 
 static bool
-extract_cond_operands (struct ivopts_data *data, tree *cond_p,
+extract_cond_operands (struct ivopts_data *data, gimple stmt,
                       tree **control_var, tree **bound,
                       struct iv **iv_var, struct iv **iv_bound)
 {
-  /* The nodes returned when COND has just one operand.  Note that you should
-     not modify anything in BOUND or IV_BOUND because of this.  */
+  /* The objects returned when COND has constant operands.  */
   static struct iv const_iv;
   static tree zero;
-  tree cond = *cond_p;
   tree *op0 = &zero, *op1 = &zero, *tmp_op;
   struct iv *iv0 = &const_iv, *iv1 = &const_iv, *tmp_iv;
   bool ret = false;
 
-  zero = integer_zero_node;
-  const_iv.step = integer_zero_node;
-
-  if (TREE_CODE (cond) == SSA_NAME)
+  if (gimple_code (stmt) == GIMPLE_COND)
     {
-      op0 = cond_p;
-      iv0 = get_iv (data, cond);
-      ret = (iv0 && !integer_zerop (iv0->step));
-      goto end;
+      op0 = gimple_cond_lhs_ptr (stmt);
+      op1 = gimple_cond_rhs_ptr (stmt);
     }
-
-  if (!COMPARISON_CLASS_P (cond))
+  else
     {
-      op0 = cond_p;
-      goto end;
+      op0 = gimple_assign_rhs1_ptr (stmt);
+      op1 = gimple_assign_rhs2_ptr (stmt);
     }
 
-  op0 = &TREE_OPERAND (cond, 0);
-  op1 = &TREE_OPERAND (cond, 1);
+  zero = integer_zero_node;
+  const_iv.step = integer_zero_node;
+
   if (TREE_CODE (*op0) == SSA_NAME)
     iv0 = get_iv (data, *op0);
   if (TREE_CODE (*op1) == SSA_NAME)
@@ -1232,16 +1238,16 @@ end:
   return ret;
 }
 
-/* Checks whether the condition *COND_P in STMT is interesting
-   and if so, records it.  */
+/* Checks whether the condition in STMT is interesting and if so,
+   records it.  */
 
 static void
-find_interesting_uses_cond (struct ivopts_data *data, tree stmt, tree *cond_p)
+find_interesting_uses_cond (struct ivopts_data *data, gimple stmt)
 {
   tree *var_p, *bound_p;
   struct iv *var_iv, *civ;
 
-  if (!extract_cond_operands (data, cond_p, &var_p, &bound_p, &var_iv, NULL))
+  if (!extract_cond_operands (data, stmt, &var_p, &bound_p, &var_iv, NULL))
     {
       find_interesting_uses_op (data, *var_p);
       find_interesting_uses_op (data, *bound_p);
@@ -1250,11 +1256,12 @@ find_interesting_uses_cond (struct ivopts_data *data, tree stmt, tree *cond_p)
 
   civ = XNEW (struct iv);
   *civ = *var_iv;
-  record_use (data, cond_p, civ, stmt, USE_COMPARE);
+  record_use (data, NULL, 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.  */
+   i.e. if all its operands are defined outside of the LOOP.  LOOP
+   should not be the function body.  */
 
 bool
 expr_invariant_in_loop_p (struct loop *loop, tree expr)
@@ -1262,12 +1269,14 @@ expr_invariant_in_loop_p (struct loop *loop, tree expr)
   basic_block def_bb;
   unsigned i, len;
 
+  gcc_assert (loop_depth (loop) > 0);
+
   if (is_gimple_min_invariant (expr))
     return true;
 
   if (TREE_CODE (expr) == SSA_NAME)
     {
-      def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (expr));
+      def_bb = gimple_bb (SSA_NAME_DEF_STMT (expr));
       if (def_bb
          && flow_bb_inside_loop_p (loop, def_bb))
        return false;
@@ -1275,7 +1284,7 @@ expr_invariant_in_loop_p (struct loop *loop, tree expr)
       return true;
     }
 
-  if (!EXPR_P (expr) && !GIMPLE_STMT_P (expr))
+  if (!EXPR_P (expr))
     return false;
 
   len = TREE_OPERAND_LENGTH (expr);
@@ -1286,6 +1295,29 @@ expr_invariant_in_loop_p (struct loop *loop, tree expr)
   return true;
 }
 
+/* Returns true if statement STMT is obviously invariant in LOOP,
+   i.e. if all its operands on the RHS are defined outside of the LOOP.
+   LOOP should not be the function body.  */
+
+bool
+stmt_invariant_in_loop_p (struct loop *loop, gimple stmt)
+{
+  unsigned i;
+  tree lhs;
+
+  gcc_assert (loop_depth (loop) > 0);
+
+  lhs = gimple_get_lhs (stmt);
+  for (i = 0; i < gimple_num_ops (stmt); i++)
+    {
+      tree op = gimple_op (stmt, i);
+      if (op != lhs && !expr_invariant_in_loop_p (loop, op))
+       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.  */
@@ -1293,7 +1325,7 @@ expr_invariant_in_loop_p (struct loop *loop, tree expr)
 struct ifs_ivopts_data
 {
   struct ivopts_data *ivopts_data;
-  tree stmt;
+  gimple stmt;
   tree step;
 };
 
@@ -1391,10 +1423,75 @@ idx_record_use (tree base, tree *idx,
   return true;
 }
 
-/* Returns true if memory reference REF may be unaligned.  */
+/* If we can prove that TOP = cst * BOT for some constant cst,
+   store cst to MUL and return true.  Otherwise return false.
+   The returned value is always sign-extended, regardless of the
+   signedness of TOP and BOT.  */
+
+static bool
+constant_multiple_of (tree top, tree bot, double_int *mul)
+{
+  tree mby;
+  enum tree_code code;
+  double_int res, p0, p1;
+  unsigned precision = TYPE_PRECISION (TREE_TYPE (top));
+
+  STRIP_NOPS (top);
+  STRIP_NOPS (bot);
+
+  if (operand_equal_p (top, bot, 0))
+    {
+      *mul = double_int_one;
+      return true;
+    }
+
+  code = TREE_CODE (top);
+  switch (code)
+    {
+    case MULT_EXPR:
+      mby = TREE_OPERAND (top, 1);
+      if (TREE_CODE (mby) != INTEGER_CST)
+       return false;
+
+      if (!constant_multiple_of (TREE_OPERAND (top, 0), bot, &res))
+       return false;
+
+      *mul = double_int_sext (double_int_mul (res, tree_to_double_int (mby)),
+                             precision);
+      return true;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      if (!constant_multiple_of (TREE_OPERAND (top, 0), bot, &p0)
+         || !constant_multiple_of (TREE_OPERAND (top, 1), bot, &p1))
+       return false;
+
+      if (code == MINUS_EXPR)
+       p1 = double_int_neg (p1);
+      *mul = double_int_sext (double_int_add (p0, p1), precision);
+      return true;
+
+    case INTEGER_CST:
+      if (TREE_CODE (bot) != INTEGER_CST)
+       return false;
+
+      p0 = double_int_sext (tree_to_double_int (top), precision);
+      p1 = double_int_sext (tree_to_double_int (bot), precision);
+      if (double_int_zero_p (p1))
+       return false;
+      *mul = double_int_sext (double_int_sdivmod (p0, p1, FLOOR_DIV_EXPR, &res),
+                             precision);
+      return double_int_zero_p (res);
+
+    default:
+      return false;
+    }
+}
+
+/* Returns true if memory reference REF with step STEP may be unaligned.  */
 
 static bool
-may_be_unaligned_p (tree ref)
+may_be_unaligned_p (tree ref, tree step)
 {
   tree base;
   tree base_type;
@@ -1418,11 +1515,20 @@ may_be_unaligned_p (tree ref)
   base_type = TREE_TYPE (base);
   base_align = TYPE_ALIGN (base_type);
 
-  if (mode != BLKmode
-      && (base_align < GET_MODE_ALIGNMENT (mode)
+  if (mode != BLKmode)
+    {
+      double_int mul;
+      tree al = build_int_cst (TREE_TYPE (step),
+                              GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT);
+
+      if (base_align < GET_MODE_ALIGNMENT (mode)
          || bitpos % GET_MODE_ALIGNMENT (mode) != 0
-         || bitpos % BITS_PER_UNIT != 0))
-    return true;
+         || bitpos % BITS_PER_UNIT != 0)
+       return true;
+    
+      if (!constant_multiple_of (step, al, &mul))
+       return true;
+    }
 
   return false;
 }
@@ -1434,21 +1540,32 @@ may_be_nonaddressable_p (tree expr)
 {
   switch (TREE_CODE (expr))
     {
+    case TARGET_MEM_REF:
+      /* TARGET_MEM_REFs are translated directly to valid MEMs on the
+        target, thus they are always addressable.  */
+      return false;
+
     case COMPONENT_REF:
       return DECL_NONADDRESSABLE_P (TREE_OPERAND (expr, 1))
             || may_be_nonaddressable_p (TREE_OPERAND (expr, 0));
 
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      return may_be_nonaddressable_p (TREE_OPERAND (expr, 0));
-
     case VIEW_CONVERT_EXPR:
       /* This kind of view-conversions may wrap non-addressable objects
         and make them look addressable.  After some processing the
         non-addressability may be uncovered again, causing ADDR_EXPRs
         of inappropriate objects to be built.  */
-      return AGGREGATE_TYPE_P (TREE_TYPE (expr))
-            && !AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
+      if (is_gimple_reg (TREE_OPERAND (expr, 0))
+         || is_gimple_min_invariant (TREE_OPERAND (expr, 0)))
+       return true;
+
+      /* ... fall through ... */
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      return may_be_nonaddressable_p (TREE_OPERAND (expr, 0));
+
+    CASE_CONVERT:
+      return true;
 
     default:
       break;
@@ -1460,7 +1577,7 @@ may_be_nonaddressable_p (tree expr)
 /* Finds addresses in *OP_P inside STMT.  */
 
 static void
-find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
+find_interesting_uses_address (struct ivopts_data *data, gimple stmt, tree *op_p)
 {
   tree base = *op_p, step = build_int_cst (sizetype, 0);
   struct iv *civ;
@@ -1468,7 +1585,7 @@ find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
 
   /* Do not play with volatile memory references.  A bit too conservative,
      perhaps, but safe.  */
-  if (stmt_ann (stmt)->has_volatile_ops)
+  if (gimple_has_volatile_ops (stmt))
     goto fail;
 
   /* Ignore bitfields for now.  Not really something terribly complicated
@@ -1476,13 +1593,6 @@ find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
   if (TREE_CODE (base) == BIT_FIELD_REF)
     goto fail;
 
-  if (may_be_nonaddressable_p (base))
-    goto fail;
-
-  if (STRICT_ALIGNMENT
-      && may_be_unaligned_p (base))
-    goto fail;
-
   base = unshare_expr (base);
 
   if (TREE_CODE (base) == TARGET_MEM_REF)
@@ -1536,6 +1646,16 @@ 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);
 
+      /* Check that the base expression is addressable.  This needs
+        to be done after substituting bases of IVs into it.  */
+      if (may_be_nonaddressable_p (base))
+       goto fail;
+
+      /* Moreover, on strict alignment platforms, check that it is
+        sufficiently aligned.  */
+      if (STRICT_ALIGNMENT && may_be_unaligned_p (base, step))
+       goto fail;
+
       base = build_fold_addr_expr (base);
 
       /* Substituting bases of IVs into the base expression might
@@ -1561,7 +1681,7 @@ fail:
 /* Finds and records invariants used in STMT.  */
 
 static void
-find_invariants_stmt (struct ivopts_data *data, tree stmt)
+find_invariants_stmt (struct ivopts_data *data, gimple stmt)
 {
   ssa_op_iter iter;
   use_operand_p use_p;
@@ -1577,61 +1697,55 @@ find_invariants_stmt (struct ivopts_data *data, tree stmt)
 /* Finds interesting uses of induction variables in the statement STMT.  */
 
 static void
-find_interesting_uses_stmt (struct ivopts_data *data, tree stmt)
+find_interesting_uses_stmt (struct ivopts_data *data, gimple stmt)
 {
   struct iv *iv;
-  tree op, lhs, rhs;
+  tree op, *lhs, *rhs;
   ssa_op_iter iter;
   use_operand_p use_p;
+  enum tree_code code;
 
   find_invariants_stmt (data, stmt);
 
-  if (TREE_CODE (stmt) == COND_EXPR)
+  if (gimple_code (stmt) == GIMPLE_COND)
     {
-      find_interesting_uses_cond (data, stmt, &COND_EXPR_COND (stmt));
+      find_interesting_uses_cond (data, stmt);
       return;
     }
 
-  if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+  if (is_gimple_assign (stmt))
     {
-      lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-      rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+      lhs = gimple_assign_lhs_ptr (stmt);
+      rhs = gimple_assign_rhs1_ptr (stmt);
 
-      if (TREE_CODE (lhs) == SSA_NAME)
+      if (TREE_CODE (*lhs) == SSA_NAME)
        {
          /* If the statement defines an induction variable, the uses are not
             interesting by themselves.  */
 
-         iv = get_iv (data, lhs);
+         iv = get_iv (data, *lhs);
 
          if (iv && !integer_zerop (iv->step))
            return;
        }
 
-      switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
+      code = gimple_assign_rhs_code (stmt);
+      if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS
+         && (REFERENCE_CLASS_P (*rhs)
+             || is_gimple_val (*rhs)))
        {
-       case tcc_comparison:
-         find_interesting_uses_cond (data, stmt,
-                                     &GIMPLE_STMT_OPERAND (stmt, 1));
-         return;
+         if (REFERENCE_CLASS_P (*rhs))
+           find_interesting_uses_address (data, stmt, rhs);
+         else
+           find_interesting_uses_op (data, *rhs);
 
-       case tcc_reference:
-         find_interesting_uses_address (data, stmt,
-                                        &GIMPLE_STMT_OPERAND (stmt, 1));
-         if (REFERENCE_CLASS_P (lhs))
-           find_interesting_uses_address (data, stmt,
-                                          &GIMPLE_STMT_OPERAND (stmt, 0));
+         if (REFERENCE_CLASS_P (*lhs))
+           find_interesting_uses_address (data, stmt, lhs);
          return;
-
-       default: ;
        }
-
-      if (REFERENCE_CLASS_P (lhs)
-         && is_gimple_val (rhs))
+      else if (TREE_CODE_CLASS (code) == tcc_comparison)
        {
-         find_interesting_uses_address (data, stmt,
-                                        &GIMPLE_STMT_OPERAND (stmt, 0));
-         find_interesting_uses_op (data, rhs);
+         find_interesting_uses_cond (data, stmt);
          return;
        }
 
@@ -1644,11 +1758,10 @@ find_interesting_uses_stmt (struct ivopts_data *data, tree stmt)
         call (memory).  */
     }
 
-  if (TREE_CODE (stmt) == PHI_NODE
-      && bb_for_stmt (stmt) == data->current_loop->header)
+  if (gimple_code (stmt) == GIMPLE_PHI
+      && gimple_bb (stmt) == data->current_loop->header)
     {
-      lhs = PHI_RESULT (stmt);
-      iv = get_iv (data, lhs);
+      iv = get_iv (data, PHI_RESULT (stmt));
 
       if (iv && !integer_zerop (iv->step))
        return;
@@ -1675,10 +1788,13 @@ find_interesting_uses_stmt (struct ivopts_data *data, tree stmt)
 static void
 find_interesting_uses_outside (struct ivopts_data *data, edge exit)
 {
-  tree phi, def;
+  gimple phi;
+  gimple_stmt_iterator psi;
+  tree def;
 
-  for (phi = phi_nodes (exit->dest); phi; phi = PHI_CHAIN (phi))
+  for (psi = gsi_start_phis (exit->dest); !gsi_end_p (psi); gsi_next (&psi))
     {
+      phi = gsi_stmt (psi);
       def = PHI_ARG_DEF_FROM_EDGE (phi, exit);
       if (is_gimple_reg (def))
        find_interesting_uses_op (data, def);
@@ -1691,8 +1807,7 @@ static void
 find_interesting_uses (struct ivopts_data *data)
 {
   basic_block bb;
-  block_stmt_iterator bsi;
-  tree phi;
+  gimple_stmt_iterator bsi;
   basic_block *body = get_loop_body (data->current_loop);
   unsigned i;
   struct version_info *info;
@@ -1711,10 +1826,10 @@ find_interesting_uses (struct ivopts_data *data)
            && !flow_bb_inside_loop_p (data->current_loop, e->dest))
          find_interesting_uses_outside (data, e);
 
-      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));
+      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+       find_interesting_uses_stmt (data, gsi_stmt (bsi));
+      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+       find_interesting_uses_stmt (data, gsi_stmt (bsi));
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -1937,7 +2052,7 @@ find_depends (tree *expr_p, int *ws ATTRIBUTE_UNUSED, void *data)
 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)
+                struct iv_use *use, gimple incremented_at)
 {
   unsigned i;
   struct iv_cand *cand = NULL;
@@ -1947,7 +2062,9 @@ add_candidate_1 (struct ivopts_data *data,
     {
       orig_type = TREE_TYPE (base);
       type = generic_type_for (orig_type);
-      if (type != orig_type)
+      /* Don't convert the base to the generic type for pointers as the generic
+        type is an integer type with the same size as the pointer type.  */
+      if (type != orig_type && !POINTER_TYPE_P (orig_type))
        {
          base = fold_convert (type, base);
          step = fold_convert (type, step);
@@ -2059,10 +2176,10 @@ add_candidate (struct ivopts_data *data,
               tree base, tree step, bool important, struct iv_use *use)
 {
   if (ip_normal_pos (data->current_loop))
-    add_candidate_1 (data, base, step, important, IP_NORMAL, use, NULL_TREE);
+    add_candidate_1 (data, base, step, important, IP_NORMAL, use, NULL);
   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_candidate_1 (data, base, step, important, IP_END, use, NULL);
 }
 
 /* Add a standard "0 + 1 * iteration" iv candidate for a
@@ -2095,7 +2212,8 @@ add_standard_iv_candidates (struct ivopts_data *data)
 static void
 add_old_iv_candidates (struct ivopts_data *data, struct iv *iv)
 {
-  tree phi, def;
+  gimple phi;
+  tree def;
   struct iv_cand *cand;
 
   add_candidate (data, iv->base, iv->step, true, NULL);
@@ -2106,7 +2224,7 @@ add_old_iv_candidates (struct ivopts_data *data, struct iv *iv)
                 iv->step, true, NULL);
 
   phi = SSA_NAME_DEF_STMT (iv->ssa_name);
-  if (TREE_CODE (phi) == PHI_NODE)
+  if (gimple_code (phi) == GIMPLE_PHI)
     {
       /* Additionally record the possibility of leaving the original iv
         untouched.  */
@@ -2144,18 +2262,24 @@ add_iv_value_candidates (struct ivopts_data *data,
 {
   unsigned HOST_WIDE_INT offset;
   tree base;
+  tree basetype;
 
   add_candidate (data, iv->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),
+  basetype = TREE_TYPE (iv->base);
+  if (POINTER_TYPE_P (basetype))
+    basetype = sizetype;
+  add_candidate (data, build_int_cst (basetype, 0),
                 iv->step, true, use);
 
-  /* Third, try removing the constant offset.  */
+  /* Third, try removing the constant offset.  Make sure to even
+     add a candidate for &a[0] vs. (T *)&a.  */
   base = strip_offset (iv->base, &offset);
-  if (offset)
+  if (offset
+      || base != iv->base)
     add_candidate (data, base, iv->step, false, use);
 }
 
@@ -2541,7 +2665,7 @@ computation_cost (tree expr)
 /* Returns variable containing the value of candidate CAND at statement AT.  */
 
 static tree
-var_at_stmt (struct loop *loop, struct iv_cand *cand, tree stmt)
+var_at_stmt (struct loop *loop, struct iv_cand *cand, gimple stmt)
 {
   if (stmt_after_increment (loop, cand, stmt))
     return cand->var_after;
@@ -2569,71 +2693,6 @@ tree_int_cst_sign_bit (const_tree t)
   return (w >> bitno) & 1;
 }
 
-/* If we can prove that TOP = cst * BOT for some constant cst,
-   store cst to MUL and return true.  Otherwise return false.
-   The returned value is always sign-extended, regardless of the
-   signedness of TOP and BOT.  */
-
-static bool
-constant_multiple_of (tree top, tree bot, double_int *mul)
-{
-  tree mby;
-  enum tree_code code;
-  double_int res, p0, p1;
-  unsigned precision = TYPE_PRECISION (TREE_TYPE (top));
-
-  STRIP_NOPS (top);
-  STRIP_NOPS (bot);
-
-  if (operand_equal_p (top, bot, 0))
-    {
-      *mul = double_int_one;
-      return true;
-    }
-
-  code = TREE_CODE (top);
-  switch (code)
-    {
-    case MULT_EXPR:
-      mby = TREE_OPERAND (top, 1);
-      if (TREE_CODE (mby) != INTEGER_CST)
-       return false;
-
-      if (!constant_multiple_of (TREE_OPERAND (top, 0), bot, &res))
-       return false;
-
-      *mul = double_int_sext (double_int_mul (res, tree_to_double_int (mby)),
-                             precision);
-      return true;
-
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-      if (!constant_multiple_of (TREE_OPERAND (top, 0), bot, &p0)
-         || !constant_multiple_of (TREE_OPERAND (top, 1), bot, &p1))
-       return false;
-
-      if (code == MINUS_EXPR)
-       p1 = double_int_neg (p1);
-      *mul = double_int_sext (double_int_add (p0, p1), precision);
-      return true;
-
-    case INTEGER_CST:
-      if (TREE_CODE (bot) != INTEGER_CST)
-       return false;
-
-      p0 = double_int_sext (tree_to_double_int (top), precision);
-      p1 = double_int_sext (tree_to_double_int (bot), precision);
-      if (double_int_zero_p (p1))
-       return false;
-      *mul = double_int_sext (double_int_sdivmod (p0, p1, FLOOR_DIV_EXPR, &res),
-                             precision);
-      return double_int_zero_p (res);
-
-    default:
-      return false;
-    }
-}
-
 /* If A is (TYPE) BA and B is (TYPE) BB, and the types of BA and BB have the
    same precision that is at least as wide as the precision of TYPE, stores
    BA to A and BB to B, and returns the type of BA.  Otherwise, returns the
@@ -2646,8 +2705,7 @@ determine_common_wider_type (tree *a, tree *b)
   tree suba, subb;
   tree atype = TREE_TYPE (*a);
 
-  if ((TREE_CODE (*a) == NOP_EXPR
-       || TREE_CODE (*a) == CONVERT_EXPR))
+  if (CONVERT_EXPR_P (*a))
     {
       suba = TREE_OPERAND (*a, 0);
       wider_type = TREE_TYPE (suba);
@@ -2657,8 +2715,7 @@ determine_common_wider_type (tree *a, tree *b)
   else
     return atype;
 
-  if ((TREE_CODE (*b) == NOP_EXPR
-       || TREE_CODE (*b) == CONVERT_EXPR))
+  if (CONVERT_EXPR_P (*b))
     {
       subb = TREE_OPERAND (*b, 0);
       if (TYPE_PRECISION (wider_type) != TYPE_PRECISION (TREE_TYPE (subb)))
@@ -2678,7 +2735,7 @@ determine_common_wider_type (tree *a, tree *b)
 
 static bool
 get_computation_aff (struct loop *loop,
-                    struct iv_use *use, struct iv_cand *cand, tree at,
+                    struct iv_use *use, struct iv_cand *cand, gimple at,
                     struct affine_tree_combination *aff)
 {
   tree ubase = use->iv->base;
@@ -2753,7 +2810,7 @@ get_computation_aff (struct loop *loop,
 
 static tree
 get_computation_at (struct loop *loop,
-                   struct iv_use *use, struct iv_cand *cand, tree at)
+                   struct iv_use *use, struct iv_cand *cand, gimple at)
 {
   aff_tree aff;
   tree type = TREE_TYPE (use->iv->base);
@@ -3013,7 +3070,7 @@ get_address_cost (bool symbol_present, bool var_present,
            {
              base = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (""));
              /* ??? We can run into trouble with some backends by presenting
-                it with symbols which havn't been properly passed through
+                it with symbols which haven't been properly passed through
                 targetm.encode_section_info.  By setting the local bit, we
                 enhance the probability of things working.  */
              SYMBOL_REF_FLAGS (base) = SYMBOL_FLAG_LOCAL;
@@ -3183,7 +3240,7 @@ force_expr_to_var_cost (tree expr)
   if (SSA_VAR_P (expr))
     return zero_cost;
 
-  if (TREE_INVARIANT (expr))
+  if (is_gimple_min_invariant (expr))
     {
       if (TREE_CODE (expr) == INTEGER_CST)
        return new_cost (integer_cost, 0);
@@ -3423,7 +3480,7 @@ difference_cost (struct ivopts_data *data,
 static comp_cost
 get_computation_cost_at (struct ivopts_data *data,
                         struct iv_use *use, struct iv_cand *cand,
-                        bool address_p, bitmap *depends_on, tree at)
+                        bool address_p, bitmap *depends_on, gimple at)
 {
   tree ubase = use->iv->base, ustep = use->iv->step;
   tree cbase, cstep;
@@ -3637,16 +3694,19 @@ determine_use_iv_cost_address (struct ivopts_data *data,
    stores it to VAL.  */
 
 static void
-cand_value_at (struct loop *loop, struct iv_cand *cand, tree at, tree niter,
+cand_value_at (struct loop *loop, struct iv_cand *cand, gimple at, tree niter,
               aff_tree *val)
 {
   aff_tree step, delta, nit;
   struct iv *iv = cand->iv;
   tree type = TREE_TYPE (iv->base);
+  tree steptype = type;
+  if (POINTER_TYPE_P (type))
+    steptype = sizetype;
 
-  tree_to_aff_combination (iv->step, type, &step);
+  tree_to_aff_combination (iv->step, steptype, &step);
   tree_to_aff_combination (niter, TREE_TYPE (niter), &nit);
-  aff_combination_convert (&nit, type);
+  aff_combination_convert (&nit, steptype);
   aff_combination_mult (&nit, &step, &delta);
   if (stmt_after_increment (loop, cand, at))
     aff_combination_add (&delta, &step);
@@ -3687,7 +3747,7 @@ iv_elimination_compare (struct ivopts_data *data, struct iv_use *use)
   basic_block ex_bb;
   edge exit;
 
-  ex_bb = bb_for_stmt (use->stmt);
+  ex_bb = gimple_bb (use->stmt);
   exit = EDGE_SUCC (ex_bb, 0);
   if (flow_bb_inside_loop_p (loop, exit->dest))
     exit = EDGE_SUCC (ex_bb, 1);
@@ -3707,18 +3767,16 @@ may_eliminate_iv (struct ivopts_data *data,
   tree nit, period;
   struct loop *loop = data->current_loop;
   aff_tree bnd;
-  double_int period_value, max_niter;
 
   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);
+  /* For now works only for exits that dominate the loop latch.
+     TODO: extend to other conditions inside loop body.  */
+  ex_bb = gimple_bb (use->stmt);
   if (use->stmt != last_stmt (ex_bb)
-      || TREE_CODE (use->stmt) != COND_EXPR)
-    return false;
-  if (!dominated_by_p (CDI_DOMINATORS, loop->latch, ex_bb))
+      || gimple_code (use->stmt) != GIMPLE_COND
+      || !dominated_by_p (CDI_DOMINATORS, loop->latch, ex_bb))
     return false;
 
   exit = EDGE_SUCC (ex_bb, 0);
@@ -3731,19 +3789,33 @@ may_eliminate_iv (struct ivopts_data *data,
   if (!nit)
     return false;
 
-  /* 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.  */
+  /* Determine whether we can use the variable to test the exit condition.
+     This is the case iff the period of the induction variable is greater
+     than the number of iterations for which the exit condition is true.  */
   period = iv_period (cand->iv);
-  if (!period)
-    return false;
 
-  /* Compare the period with the estimate on the number of iterations of the
-     loop.  */
-  if (!estimated_loop_iterations (loop, true, &max_niter))
-    return false;
-  period_value = tree_to_double_int (period);
-  if (double_int_ucmp (period_value, max_niter) <= 0)
+  /* If the number of iterations is constant, compare against it directly.  */
+  if (TREE_CODE (nit) == INTEGER_CST)
+    {
+      if (!tree_int_cst_lt (nit, period))
+       return false;
+    }
+
+  /* If not, and if this is the only possible exit of the loop, see whether
+     we can get a conservative estimate on the number of iterations of the
+     entire loop and compare against that instead.  */
+  else if (loop_only_exit_p (loop, exit))
+    {
+      double_int period_value, max_niter;
+      if (!estimated_loop_iterations (loop, true, &max_niter))
+       return false;
+      period_value = tree_to_double_int (period);
+      if (double_int_ucmp (max_niter, period_value) >= 0)
+       return false;
+    }
+
+  /* Otherwise, punt.  */
+  else
     return false;
 
   cand_value_at (loop, cand, use->stmt, nit, &bnd);
@@ -3783,7 +3855,7 @@ determine_use_iv_cost_condition (struct ivopts_data *data,
 
   /* Try expressing the original giv.  If it is compared with an invariant,
      note that we cannot get rid of it.  */
-  ok = extract_cond_operands (data, use->op_p, NULL, NULL, NULL, &cmp_iv);
+  ok = extract_cond_operands (data, use->stmt, NULL, NULL, NULL, &cmp_iv);
   gcc_assert (ok);
 
   express_cost = get_computation_cost (data, use, cand, false,
@@ -3941,7 +4013,7 @@ determine_iv_cost (struct ivopts_data *data, struct iv_cand *cand)
   cost = cost_step + cost_base.cost / AVG_LOOP_NITER (current_loop);
 
   /* Prefer the original ivs unless we may gain something by replacing it.
-     The reason is to makee debugging simpler; so this is not relevant for
+     The reason is to make debugging simpler; so this is not relevant for
      artificial ivs created by other optimization passes.  */
   if (cand->pos != IP_ORIGINAL
       || DECL_ARTIFICIAL (SSA_NAME_VAR (cand->var_before)))
@@ -3999,7 +4071,9 @@ static void
 determine_set_costs (struct ivopts_data *data)
 {
   unsigned j, n;
-  tree phi, op;
+  gimple phi;
+  gimple_stmt_iterator psi;
+  tree op;
   struct loop *loop = data->current_loop;
   bitmap_iterator bi;
 
@@ -4032,8 +4106,9 @@ determine_set_costs (struct ivopts_data *data)
     }
 
   n = 0;
-  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
+  for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
     {
+      phi = gsi_stmt (psi);
       op = PHI_RESULT (phi);
 
       if (!is_gimple_reg (op))
@@ -4874,7 +4949,7 @@ find_optimal_iv_set (struct ivopts_data *data)
 static void
 create_new_iv (struct ivopts_data *data, struct iv_cand *cand)
 {
-  block_stmt_iterator incr_pos;
+  gimple_stmt_iterator incr_pos;
   tree base;
   bool after = false;
 
@@ -4884,11 +4959,11 @@ create_new_iv (struct ivopts_data *data, struct iv_cand *cand)
   switch (cand->pos)
     {
     case IP_NORMAL:
-      incr_pos = bsi_last (ip_normal_pos (data->current_loop));
+      incr_pos = gsi_last_bb (ip_normal_pos (data->current_loop));
       break;
 
     case IP_END:
-      incr_pos = bsi_last (ip_end_pos (data->current_loop));
+      incr_pos = gsi_last_bb (ip_end_pos (data->current_loop));
       after = true;
       break;
 
@@ -4933,17 +5008,15 @@ create_new_ivs (struct ivopts_data *data, struct iv_ca *set)
    is true, remove also the ssa name defined by the statement.  */
 
 static void
-remove_statement (tree stmt, bool including_defined_name)
+remove_statement (gimple stmt, bool including_defined_name)
 {
-  if (TREE_CODE (stmt) == PHI_NODE)
-    {
-      remove_phi_node (stmt, NULL_TREE, including_defined_name);
-    }
+  gimple_stmt_iterator bsi = gsi_for_stmt (stmt);
+
+  if (gimple_code (stmt) == GIMPLE_PHI)
+    remove_phi_node (&bsi, including_defined_name);
   else
     {
-      block_stmt_iterator bsi = bsi_for_stmt (stmt);
-
-      bsi_remove (&bsi, true);
+      gsi_remove (&bsi, true);
       release_defs (stmt); 
     }
 }
@@ -4956,8 +5029,9 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data,
                            struct iv_use *use, struct iv_cand *cand)
 {
   tree comp;
-  tree op, tgt, ass;
-  block_stmt_iterator bsi;
+  tree op, tgt;
+  gimple ass;
+  gimple_stmt_iterator bsi;
 
   /* An important special case -- if we are asked to express value of
      the original iv by itself, just exit; there is no need to
@@ -4967,10 +5041,10 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data,
       && cand->incremented_at == use->stmt)
     {
       tree step, ctype, utype;
-      enum tree_code incr_code = PLUS_EXPR;
+      enum tree_code incr_code = PLUS_EXPR, old_code;
 
-      gcc_assert (TREE_CODE (use->stmt) == GIMPLE_MODIFY_STMT);
-      gcc_assert (GIMPLE_STMT_OPERAND (use->stmt, 0) == cand->var_after);
+      gcc_assert (is_gimple_assign (use->stmt));
+      gcc_assert (gimple_assign_lhs (use->stmt) == cand->var_after);
 
       step = cand->iv->step;
       ctype = TREE_TYPE (step);
@@ -4986,16 +5060,16 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data,
         computations in the loop -- otherwise, the computation
         we rely upon may be removed in remove_unused_ivs,
         thus leading to ICE.  */
-      op = GIMPLE_STMT_OPERAND (use->stmt, 1);
-      if (TREE_CODE (op) == PLUS_EXPR
-         || TREE_CODE (op) == MINUS_EXPR
-         || TREE_CODE (op) == POINTER_PLUS_EXPR)
+      old_code = gimple_assign_rhs_code (use->stmt);
+      if (old_code == PLUS_EXPR
+         || old_code == MINUS_EXPR
+         || old_code == POINTER_PLUS_EXPR)
        {
-         if (TREE_OPERAND (op, 0) == cand->var_before)
-           op = TREE_OPERAND (op, 1);
-         else if (TREE_CODE (op) != MINUS_EXPR
-                  && TREE_OPERAND (op, 1) == cand->var_before)
-           op = TREE_OPERAND (op, 0);
+         if (gimple_assign_rhs1 (use->stmt) == cand->var_before)
+           op = gimple_assign_rhs2 (use->stmt);
+         else if (old_code != MINUS_EXPR
+                  && gimple_assign_rhs2 (use->stmt) == cand->var_before)
+           op = gimple_assign_rhs1 (use->stmt);
          else
            op = NULL_TREE;
        }
@@ -5020,39 +5094,41 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data,
       gcc_assert (comp != NULL_TREE);
     }
 
-  switch (TREE_CODE (use->stmt))
+  switch (gimple_code (use->stmt))
     {
-    case PHI_NODE:
+    case GIMPLE_PHI:
       tgt = PHI_RESULT (use->stmt);
 
       /* If we should keep the biv, do not replace it.  */
       if (name_info (data, tgt)->preserve_biv)
        return;
 
-      bsi = bsi_after_labels (bb_for_stmt (use->stmt));
+      bsi = gsi_after_labels (gimple_bb (use->stmt));
       break;
 
-    case GIMPLE_MODIFY_STMT:
-      tgt = GIMPLE_STMT_OPERAND (use->stmt, 0);
-      bsi = bsi_for_stmt (use->stmt);
+    case GIMPLE_ASSIGN:
+      tgt = gimple_assign_lhs (use->stmt);
+      bsi = gsi_for_stmt (use->stmt);
       break;
 
     default:
       gcc_unreachable ();
     }
 
-  op = force_gimple_operand_bsi (&bsi, comp, false, SSA_NAME_VAR (tgt),
-                                true, BSI_SAME_STMT);
+  op = force_gimple_operand_gsi (&bsi, comp, false, SSA_NAME_VAR (tgt),
+                                true, GSI_SAME_STMT);
 
-  if (TREE_CODE (use->stmt) == PHI_NODE)
+  if (gimple_code (use->stmt) == GIMPLE_PHI)
     {
-      ass = build_gimple_modify_stmt (tgt, op);
-      bsi_insert_before (&bsi, ass, BSI_SAME_STMT);
+      ass = gimple_build_assign (tgt, op);
+      gsi_insert_before (&bsi, ass, GSI_SAME_STMT);
       remove_statement (use->stmt, false);
-      SSA_NAME_DEF_STMT (tgt) = ass;
     }
   else
-    GIMPLE_STMT_OPERAND (use->stmt, 1) = op;
+    {
+      gimple_assign_set_rhs_from_tree (&bsi, op);
+      use->stmt = gsi_stmt (bsi);
+    }
 }
 
 /* Replaces ssa name in index IDX by its basic variable.  Callback for
@@ -5114,9 +5190,6 @@ get_ref_tag (tree ref, tree orig)
        break;
     }
 
-  if (aref && SSA_VAR_P (aref) && get_subvars_for_var (aref))
-    return aref;
-
   if (!var)
     return NULL_TREE;
 
@@ -5174,7 +5247,7 @@ rewrite_use_address (struct ivopts_data *data,
                     struct iv_use *use, struct iv_cand *cand)
 {
   aff_tree aff;
-  block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
+  gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
   tree ref;
   bool ok;
 
@@ -5195,7 +5268,7 @@ rewrite_use_compare (struct ivopts_data *data,
                     struct iv_use *use, struct iv_cand *cand)
 {
   tree comp, *var_p, op, bound;
-  block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
+  gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
   enum tree_code compare;
   struct cost_pair *cp = get_use_iv_cost (data, use, cand);
   bool ok;
@@ -5208,10 +5281,12 @@ rewrite_use_compare (struct ivopts_data *data,
 
       compare = iv_elimination_compare (data, use);
       bound = unshare_expr (fold_convert (var_type, bound));
-      op = force_gimple_operand_bsi (&bsi, bound, true, NULL_TREE,
-                                    true, BSI_SAME_STMT);
+      op = force_gimple_operand_gsi (&bsi, bound, true, NULL_TREE,
+                                    true, GSI_SAME_STMT);
 
-      *use->op_p = build2 (compare, boolean_type_node, var, op);
+      gimple_cond_set_lhs (use->stmt, var);
+      gimple_cond_set_code (use->stmt, compare);
+      gimple_cond_set_rhs (use->stmt, op);
       return;
     }
 
@@ -5220,11 +5295,11 @@ rewrite_use_compare (struct ivopts_data *data,
   comp = get_computation (data->current_loop, use, cand);
   gcc_assert (comp != NULL_TREE);
 
-  ok = extract_cond_operands (data, use->op_p, &var_p, NULL, NULL, NULL);
+  ok = extract_cond_operands (data, use->stmt, &var_p, NULL, NULL, NULL);
   gcc_assert (ok);
 
-  *var_p = force_gimple_operand_bsi (&bsi, comp, true, SSA_NAME_VAR (*var_p),
-                                    true, BSI_SAME_STMT);
+  *var_p = force_gimple_operand_gsi (&bsi, comp, true, SSA_NAME_VAR (*var_p),
+                                    true, GSI_SAME_STMT);
 }
 
 /* Rewrites USE using candidate CAND.  */
@@ -5404,7 +5479,7 @@ tree_ssa_iv_optimize_loop (struct ivopts_data *data, struct loop *loop)
        {
          fprintf (dump_file, "  single exit %d -> %d, exit condition ",
                   exit->src->index, exit->dest->index);
-         print_generic_expr (dump_file, last_stmt (exit->src), TDF_SLIM);
+         print_gimple_stmt (dump_file, last_stmt (exit->src), 0, TDF_SLIM);
          fprintf (dump_file, "\n");
        }