OSDN Git Service

PR tree-optimization/50596
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-pre.c
index 6e45720..60ae35c 100644 (file)
@@ -484,10 +484,12 @@ static tree pretemp;
 static tree storetemp;
 static tree prephitemp;
 
-/* Set of blocks with statements that have had its EH information
-   cleaned up.  */
+/* Set of blocks with statements that have had their EH properties changed.  */
 static bitmap need_eh_cleanup;
 
+/* Set of blocks with statements that have had their AB properties changed.  */
+static bitmap need_ab_cleanup;
+
 /* The phi_translate_table caches phi translations for a given
    expression and predecessor.  */
 
@@ -578,8 +580,7 @@ phi_trans_add (pre_expr e, pre_expr v, basic_block pred)
 
   slot = htab_find_slot_with_hash (phi_translate_table, new_pair,
                                   new_pair->hashcode, INSERT);
-  if (*slot)
-    free (*slot);
+  free (*slot);
   *slot = (void *) new_pair;
 }
 
@@ -893,9 +894,7 @@ bitmap_value_insert_into_set (bitmap_set_t set, pre_expr expr)
 {
   unsigned int val = get_expr_value_id (expr);
 
-#ifdef ENABLE_CHECKING
-  gcc_assert (expr->id == get_or_alloc_expression_id (expr));
-#endif
+  gcc_checking_assert (expr->id == get_or_alloc_expression_id (expr));
 
   /* Constant values are always considered to be part of the set.  */
   if (value_id_constant_p (val))
@@ -1151,14 +1150,6 @@ fully_constant_expression (pre_expr e)
        vn_nary_op_t nary = PRE_EXPR_NARY (e);
        switch (TREE_CODE_CLASS (nary->opcode))
          {
-         case tcc_expression:
-           if (nary->opcode == TRUTH_NOT_EXPR)
-             goto do_unary;
-           if (nary->opcode != TRUTH_AND_EXPR
-               && nary->opcode != TRUTH_OR_EXPR
-               && nary->opcode != TRUTH_XOR_EXPR)
-             return e;
-           /* Fallthrough.  */
          case tcc_binary:
          case tcc_comparison:
            {
@@ -1200,7 +1191,6 @@ fully_constant_expression (pre_expr e)
              return e;
            /* Fallthrough.  */
          case tcc_unary:
-do_unary:
            {
              /* We have to go from trees to pre exprs to value ids to
                 constants.  */
@@ -1409,7 +1399,7 @@ get_representative_for (const pre_expr e)
   if (!pretemp || exprtype != TREE_TYPE (pretemp))
     {
       pretemp = create_tmp_reg (exprtype, "pretmp");
-      get_var_ann (pretemp);
+      add_referenced_var (pretemp);
     }
 
   name = make_ssa_name (pretemp, gimple_build_nop ());
@@ -1453,20 +1443,18 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
        unsigned int i;
        bool changed = false;
        vn_nary_op_t nary = PRE_EXPR_NARY (expr);
-       struct vn_nary_op_s newnary;
-       /* The NARY structure is only guaranteed to have been
-          allocated to the nary->length operands.  */
-       memcpy (&newnary, nary, (sizeof (struct vn_nary_op_s)
-                                - sizeof (tree) * (4 - nary->length)));
+       vn_nary_op_t newnary = XALLOCAVAR (struct vn_nary_op_s,
+                                          sizeof_vn_nary_op (nary->length));
+       memcpy (newnary, nary, sizeof_vn_nary_op (nary->length));
 
-       for (i = 0; i < newnary.length; i++)
+       for (i = 0; i < newnary->length; i++)
          {
-           if (TREE_CODE (newnary.op[i]) != SSA_NAME)
+           if (TREE_CODE (newnary->op[i]) != SSA_NAME)
              continue;
            else
              {
                 pre_expr leader, result;
-               unsigned int op_val_id = VN_INFO (newnary.op[i])->value_id;
+               unsigned int op_val_id = VN_INFO (newnary->op[i])->value_id;
                leader = find_leader_in_sets (op_val_id, set1, set2);
                 result = phi_translate (leader, set1, set2, pred, phiblock);
                if (result && result != leader)
@@ -1474,12 +1462,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                    tree name = get_representative_for (result);
                    if (!name)
                      return NULL;
-                   newnary.op[i] = name;
+                   newnary->op[i] = name;
                  }
                else if (!result)
                  return NULL;
 
-               changed |= newnary.op[i] != nary->op[i];
+               changed |= newnary->op[i] != nary->op[i];
              }
          }
        if (changed)
@@ -1487,13 +1475,10 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            pre_expr constant;
            unsigned int new_val_id;
 
-           tree result = vn_nary_op_lookup_pieces (newnary.length,
-                                                   newnary.opcode,
-                                                   newnary.type,
-                                                   newnary.op[0],
-                                                   newnary.op[1],
-                                                   newnary.op[2],
-                                                   newnary.op[3],
+           tree result = vn_nary_op_lookup_pieces (newnary->length,
+                                                   newnary->opcode,
+                                                   newnary->type,
+                                                   &newnary->op[0],
                                                    &nary);
            if (result && is_gimple_min_invariant (result))
              return get_or_alloc_expr_for_constant (result);
@@ -1517,13 +1502,10 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                VEC_safe_grow_cleared (bitmap_set_t, heap,
                                       value_expressions,
                                       get_max_value_id() + 1);
-               nary = vn_nary_op_insert_pieces (newnary.length,
-                                                newnary.opcode,
-                                                newnary.type,
-                                                newnary.op[0],
-                                                newnary.op[1],
-                                                newnary.op[2],
-                                                newnary.op[3],
+               nary = vn_nary_op_insert_pieces (newnary->length,
+                                                newnary->opcode,
+                                                newnary->type,
+                                                &newnary->op[0],
                                                 result, new_val_id);
                PRE_EXPR_NARY (expr) = nary;
                constant = fully_constant_expression (expr);
@@ -1681,7 +1663,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            tree result = vn_reference_lookup_pieces (newvuse, ref->set,
                                                      ref->type,
                                                      newoperands,
-                                                     &newref, true);
+                                                     &newref, VN_WALK);
            if (result)
              VEC_free (vn_reference_op_s, heap, newoperands);
 
@@ -1691,6 +1673,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                result = fold_build1 (VIEW_CONVERT_EXPR, ref->type, result);
                converted = true;
              }
+           else if (!result && newref
+                    && !useless_type_conversion_p (ref->type, newref->type))
+             {
+               VEC_free (vn_reference_op_s, heap, newoperands);
+               return NULL;
+             }
 
            if (result && is_gimple_min_invariant (result))
              {
@@ -1712,9 +1700,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
 
                nresult = vn_nary_op_lookup_pieces (1, TREE_CODE (result),
                                                    TREE_TYPE (result),
-                                                   TREE_OPERAND (result, 0),
-                                                   NULL_TREE, NULL_TREE,
-                                                   NULL_TREE,
+                                                   &TREE_OPERAND (result, 0),
                                                    &nary);
                if (nresult && is_gimple_min_invariant (nresult))
                  return get_or_alloc_expr_for_constant (nresult);
@@ -1738,9 +1724,8 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                                           get_max_value_id() + 1);
                    nary = vn_nary_op_insert_pieces (1, TREE_CODE (result),
                                                     TREE_TYPE (result),
-                                                    TREE_OPERAND (result, 0),
-                                                    NULL_TREE, NULL_TREE,
-                                                    NULL_TREE, NULL_TREE,
+                                                    &TREE_OPERAND (result, 0),
+                                                    NULL_TREE,
                                                     new_val_id);
                    PRE_EXPR_NARY (expr) = nary;
                    constant = fully_constant_expression (expr);
@@ -2594,6 +2579,10 @@ compute_antic (void)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Starting iteration %d\n", num_iterations);
+      /* ???  We need to clear our PHI translation cache here as the
+         ANTIC sets shrink and we restrict valid translations to
+        those having operands with leaders in ANTIC.  Same below
+        for PA ANTIC computation.  */
       num_iterations++;
       changed = false;
       for (i = n_basic_blocks - NUM_FIXED_BLOCKS - 1; i >= 0; i--)
@@ -2606,10 +2595,8 @@ compute_antic (void)
                                                      block->index));
            }
        }
-#ifdef ENABLE_CHECKING
       /* Theoretically possible, but *highly* unlikely.  */
-      gcc_assert (num_iterations < 500);
-#endif
+      gcc_checking_assert (num_iterations < 500);
     }
 
   statistics_histogram_event (cfun, "compute_antic iterations",
@@ -2638,10 +2625,8 @@ compute_antic (void)
                                                            block->index));
                }
            }
-#ifdef ENABLE_CHECKING
          /* Theoretically possible, but *highly* unlikely.  */
-         gcc_assert (num_iterations < 500);
-#endif
+         gcc_checking_assert (num_iterations < 500);
        }
       statistics_histogram_event (cfun, "compute_partial_antic iterations",
                                  num_iterations);
@@ -2651,11 +2636,13 @@ compute_antic (void)
 }
 
 /* Return true if we can value number the call in STMT.  This is true
-   if we have a pure or constant call.  */
+   if we have a pure or constant call to a real function.  */
 
 static bool
 can_value_number_call (gimple stmt)
 {
+  if (gimple_call_internal_p (stmt))
+    return false;
   if (gimple_call_flags (stmt) & (ECF_PURE | ECF_CONST))
     return true;
   return false;
@@ -2764,7 +2751,7 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
            gcc_assert (base);
            offset = int_const_binop (PLUS_EXPR, offset,
                                      build_int_cst (TREE_TYPE (offset),
-                                                    off), 0);
+                                                    off));
            baseop = build_fold_addr_expr (base);
          }
        return fold_build2 (MEM_REF, currop->type, baseop, offset);
@@ -2822,26 +2809,6 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
        return folded;
       }
       break;
-    case MISALIGNED_INDIRECT_REF:
-      {
-       tree folded;
-       tree genop1 = create_component_ref_by_pieces_1 (block, ref,
-                                                       operand,
-                                                       stmts, domstmt);
-       if (!genop1)
-         return NULL_TREE;
-       genop1 = fold_convert (build_pointer_type (currop->type),
-                              genop1);
-
-       if (currop->opcode == MISALIGNED_INDIRECT_REF)
-         folded = fold_build2 (currop->opcode, currop->type,
-                               genop1, currop->op1);
-       else
-         folded = fold_build1 (currop->opcode, currop->type,
-                               genop1);
-       return folded;
-      }
-      break;
     case BIT_FIELD_REF:
       {
        tree folded;
@@ -2888,8 +2855,11 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
          return NULL_TREE;
        if (genop2)
          {
-           /* Drop zero minimum index.  */
-           if (tree_int_cst_equal (genop2, integer_zero_node))
+           tree domain_type = TYPE_DOMAIN (TREE_TYPE (genop0));
+           /* Drop zero minimum index if redundant.  */
+           if (integer_zerop (genop2)
+               && (!domain_type
+                   || integer_zerop (TYPE_MIN_VALUE (domain_type))))
              genop2 = NULL_TREE;
            else
              {
@@ -3106,50 +3076,53 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
     case NARY:
       {
        vn_nary_op_t nary = PRE_EXPR_NARY (expr);
-       switch (nary->length)
+       tree genop[4];
+       unsigned i;
+       for (i = 0; i < nary->length; ++i)
          {
-         case 2:
-           {
-             pre_expr op1 = get_or_alloc_expr_for (nary->op[0]);
-             pre_expr op2 = get_or_alloc_expr_for (nary->op[1]);
-             tree genop1 = find_or_generate_expression (block, op1,
-                                                        stmts, domstmt);
-             tree genop2 = find_or_generate_expression (block, op2,
-                                                        stmts, domstmt);
-             if (!genop1 || !genop2)
-               return NULL_TREE;
-             /* Ensure op2 is a sizetype for POINTER_PLUS_EXPR.  It
-                may be a constant with the wrong type.  */
-             if (nary->opcode == POINTER_PLUS_EXPR)
-               {
-                 genop1 = fold_convert (nary->type, genop1);
-                 genop2 = fold_convert (sizetype, genop2);
-               }
-             else
-               {
-                 genop1 = fold_convert (TREE_TYPE (nary->op[0]), genop1);
-                 genop2 = fold_convert (TREE_TYPE (nary->op[1]), genop2);
-               }
-
-             folded = fold_build2 (nary->opcode, nary->type,
-                                   genop1, genop2);
-           }
-           break;
-         case 1:
-           {
-             pre_expr op1 = get_or_alloc_expr_for (nary->op[0]);
-             tree genop1 = find_or_generate_expression (block, op1,
-                                                        stmts, domstmt);
-             if (!genop1)
-               return NULL_TREE;
-             genop1 = fold_convert (TREE_TYPE (nary->op[0]), genop1);
-
-             folded = fold_build1 (nary->opcode, nary->type,
-                                   genop1);
-           }
-           break;
-         default:
-           return NULL_TREE;
+           pre_expr op = get_or_alloc_expr_for (nary->op[i]);
+           genop[i] = find_or_generate_expression (block, op,
+                                                   stmts, domstmt);
+           if (!genop[i])
+             return NULL_TREE;
+           /* Ensure genop[] is properly typed for POINTER_PLUS_EXPR.  It
+              may have conversions stripped.  */
+           if (nary->opcode == POINTER_PLUS_EXPR)
+             {
+               if (i == 0)
+                 genop[i] = fold_convert (nary->type, genop[i]);
+               else if (i == 1)
+                 genop[i] = convert_to_ptrofftype (genop[i]);
+             }
+           else
+             genop[i] = fold_convert (TREE_TYPE (nary->op[i]), genop[i]);
+         }
+       if (nary->opcode == CONSTRUCTOR)
+         {
+           VEC(constructor_elt,gc) *elts = NULL;
+           for (i = 0; i < nary->length; ++i)
+             CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, genop[i]);
+           folded = build_constructor (nary->type, elts);
+         }
+       else
+         {
+           switch (nary->length)
+             {
+             case 1:
+               folded = fold_build1 (nary->opcode, nary->type,
+                                     genop[0]);
+               break;
+             case 2:
+               folded = fold_build2 (nary->opcode, nary->type,
+                                     genop[0], genop[1]);
+               break;
+             case 3:
+               folded = fold_build3 (nary->opcode, nary->type,
+                                     genop[0], genop[1], genop[3]);
+               break;
+             default:
+               gcc_unreachable ();
+             }
          }
       }
       break;
@@ -3197,10 +3170,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
   /* Build and insert the assignment of the end result to the temporary
      that we will return.  */
   if (!pretemp || exprtype != TREE_TYPE (pretemp))
-    {
-      pretemp = create_tmp_reg (exprtype, "pretmp");
-      get_var_ann (pretemp);
-    }
+    pretemp = create_tmp_reg (exprtype, "pretmp");
 
   temp = pretemp;
   add_referenced_var (temp);
@@ -3216,6 +3186,11 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
   /* All the symbols in NEWEXPR should be put into SSA form.  */
   mark_symbols_for_renaming (newstmt);
 
+  /* Fold the last statement.  */
+  gsi = gsi_last (*stmts);
+  if (fold_stmt_inplace (&gsi))
+    update_stmt (gsi_stmt (gsi));
+
   /* Add a value number to the temporary.
      The value may already exist in either NEW_SETS, or AVAIL_OUT, because
      we are creating the expression by pieces, and this particular piece of
@@ -3460,10 +3435,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
 
   /* Now build a phi for the new variable.  */
   if (!prephitemp || TREE_TYPE (prephitemp) != type)
-    {
-      prephitemp = create_tmp_var (type, "prephitmp");
-      get_var_ann (prephitemp);
-    }
+    prephitemp = create_tmp_var (type, "prephitmp");
 
   temp = prephitemp;
   add_referenced_var (temp);
@@ -3631,11 +3603,23 @@ do_regular_insertion (basic_block block, basic_block dom)
             already existing along every predecessor, and
             it's defined by some predecessor, it is
             partially redundant.  */
-         if (!cant_insert && !all_same && by_some && do_insertion
-             && dbg_cnt (treepre_insert))
+         if (!cant_insert && !all_same && by_some)
            {
-             if (insert_into_preds_of_block (block, get_expression_id (expr),
-                                             avail))
+             if (!do_insertion)
+               {
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "Skipping partial redundancy for "
+                              "expression ");
+                     print_pre_expr (dump_file, expr);
+                     fprintf (dump_file, " (%04d), no redundancy on to be "
+                              "optimized for speed edge\n", val);
+                   }
+               }
+             else if (dbg_cnt (treepre_insert)
+                      && insert_into_preds_of_block (block,
+                                                     get_expression_id (expr),
+                                                     avail))
                new_stuff = true;
            }
          /* If all edges produce the same value and that value is
@@ -4023,7 +4007,7 @@ compute_avail (void)
                copy_reference_ops_from_call (stmt, &ops);
                vn_reference_lookup_pieces (gimple_vuse (stmt), 0,
                                            gimple_expr_type (stmt),
-                                           ops, &ref, false);
+                                           ops, &ref, VN_NOWALK);
                VEC_free (vn_reference_op_s, heap, ops);
                if (!ref)
                  continue;
@@ -4066,9 +4050,8 @@ compute_avail (void)
                      vn_nary_op_lookup_pieces (gimple_num_ops (stmt) - 1,
                                                gimple_assign_rhs_code (stmt),
                                                gimple_expr_type (stmt),
-                                               gimple_assign_rhs1 (stmt),
-                                               gimple_assign_rhs2 (stmt),
-                                               NULL_TREE, NULL_TREE, &nary);
+                                               gimple_assign_rhs1_ptr (stmt),
+                                               &nary);
 
                      if (!nary)
                        continue;
@@ -4093,7 +4076,7 @@ compute_avail (void)
 
                      vn_reference_lookup (gimple_assign_rhs1 (stmt),
                                           gimple_vuse (stmt),
-                                          true, &ref);
+                                          VN_WALK, &ref);
                      if (!ref)
                        continue;
 
@@ -4184,6 +4167,7 @@ static unsigned int
 eliminate (void)
 {
   VEC (gimple, heap) *to_remove = NULL;
+  VEC (gimple, heap) *to_update = NULL;
   basic_block b;
   unsigned int todo = 0;
   gimple_stmt_iterator gsi;
@@ -4273,6 +4257,10 @@ eliminate (void)
                      || TREE_CODE (rhs) != SSA_NAME
                      || may_propagate_copy (rhs, sprime)))
                {
+                 bool can_make_abnormal_goto
+                   = is_gimple_call (stmt)
+                     && stmt_can_make_abnormal_goto (stmt);
+
                  gcc_assert (sprime != rhs);
 
                  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -4301,14 +4289,24 @@ eliminate (void)
                  stmt = gsi_stmt (gsi);
                  update_stmt (stmt);
 
-                 /* If we removed EH side effects from the statement, clean
+                 /* If we removed EH side-effects from the statement, clean
                     its EH information.  */
                  if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
                    {
                      bitmap_set_bit (need_eh_cleanup,
                                      gimple_bb (stmt)->index);
                      if (dump_file && (dump_flags & TDF_DETAILS))
-                       fprintf (dump_file, "  Removed EH side effects.\n");
+                       fprintf (dump_file, "  Removed EH side-effects.\n");
+                   }
+
+                 /* Likewise for AB side-effects.  */
+                 if (can_make_abnormal_goto
+                     && !stmt_can_make_abnormal_goto (stmt))
+                   {
+                     bitmap_set_bit (need_ab_cleanup,
+                                     gimple_bb (stmt)->index);
+                     if (dump_file && (dump_flags & TDF_DETAILS))
+                       fprintf (dump_file, "  Removed AB side-effects.\n");
                    }
                }
            }
@@ -4323,7 +4321,7 @@ eliminate (void)
              tree rhs = gimple_assign_rhs1 (stmt);
              tree val;
              val = vn_reference_lookup (gimple_assign_lhs (stmt),
-                                        gimple_vuse (stmt), true, NULL);
+                                        gimple_vuse (stmt), VN_WALK, NULL);
              if (TREE_CODE (rhs) == SSA_NAME)
                rhs = VN_INFO (rhs)->valnum;
              if (val
@@ -4365,13 +4363,27 @@ eliminate (void)
            }
          /* Visit indirect calls and turn them into direct calls if
             possible.  */
-         if (gimple_code (stmt) == GIMPLE_CALL
-             && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
+         if (is_gimple_call (stmt))
            {
-             tree fn = VN_INFO (gimple_call_fn (stmt))->valnum;
-             if (TREE_CODE (fn) == ADDR_EXPR
-                 && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
+             tree orig_fn = gimple_call_fn (stmt);
+             tree fn;
+             if (!orig_fn)
+               continue;
+             if (TREE_CODE (orig_fn) == SSA_NAME)
+               fn = VN_INFO (orig_fn)->valnum;
+             else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
+                      && TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
+               fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
+             else
+               continue;
+             if (gimple_call_addr_fndecl (fn) != NULL_TREE
+                 && useless_type_conversion_p (TREE_TYPE (orig_fn),
+                                               TREE_TYPE (fn)))
                {
+                 bool can_make_abnormal_goto
+                   = stmt_can_make_abnormal_goto (stmt);
+                 bool was_noreturn = gimple_call_noreturn_p (stmt);
+
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    {
                      fprintf (dump_file, "Replacing call target with ");
@@ -4381,13 +4393,31 @@ eliminate (void)
                    }
 
                  gimple_call_set_fn (stmt, fn);
-                 update_stmt (stmt);
+                 VEC_safe_push (gimple, heap, to_update, stmt);
+
+                 /* When changing a call into a noreturn call, cfg cleanup
+                    is needed to fix up the noreturn call.  */
+                 if (!was_noreturn && gimple_call_noreturn_p (stmt))
+                   todo |= TODO_cleanup_cfg;
+
+                 /* If we removed EH side-effects from the statement, clean
+                    its EH information.  */
                  if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
                    {
                      bitmap_set_bit (need_eh_cleanup,
                                      gimple_bb (stmt)->index);
                      if (dump_file && (dump_flags & TDF_DETAILS))
-                       fprintf (dump_file, "  Removed EH side effects.\n");
+                       fprintf (dump_file, "  Removed EH side-effects.\n");
+                   }
+
+                 /* Likewise for AB side-effects.  */
+                 if (can_make_abnormal_goto
+                     && !stmt_can_make_abnormal_goto (stmt))
+                   {
+                     bitmap_set_bit (need_ab_cleanup,
+                                     gimple_bb (stmt)->index);
+                     if (dump_file && (dump_flags & TDF_DETAILS))
+                       fprintf (dump_file, "  Removed AB side-effects.\n");
                    }
 
                  /* Changing an indirect call to a direct call may
@@ -4515,6 +4545,13 @@ eliminate (void)
     }
   VEC_free (gimple, heap, to_remove);
 
+  /* We cannot update call statements with virtual operands during
+     SSA walk.  This might remove them which in turn makes our
+     VN lattice invalid.  */
+  FOR_EACH_VEC_ELT (gimple, to_update, i, stmt)
+    update_stmt (stmt);
+  VEC_free (gimple, heap, to_update);
+
   return todo;
 }
 
@@ -4766,6 +4803,7 @@ init_pre (bool do_fre)
     }
 
   need_eh_cleanup = BITMAP_ALLOC (NULL);
+  need_ab_cleanup = BITMAP_ALLOC (NULL);
 }
 
 
@@ -4797,6 +4835,14 @@ fini_pre (bool do_fre)
 
   BITMAP_FREE (need_eh_cleanup);
 
+  if (!bitmap_empty_p (need_ab_cleanup))
+    {
+      gimple_purge_all_dead_abnormal_call_edges (need_ab_cleanup);
+      cleanup_tree_cfg ();
+    }
+
+  BITMAP_FREE (need_ab_cleanup);
+
   if (!do_fre)
     loop_optimizer_finalize ();
 }
@@ -4816,7 +4862,7 @@ execute_pre (bool do_fre)
   if (!do_fre)
     loop_optimizer_init (LOOPS_NORMAL);
 
-  if (!run_scc_vn ())
+  if (!run_scc_vn (do_fre ? VN_WALKREWRITE : VN_WALK))
     {
       if (!do_fre)
        loop_optimizer_finalize ();
@@ -4870,13 +4916,26 @@ execute_pre (bool do_fre)
   statistics_counter_event (cfun, "Constified", pre_stats.constified);
 
   clear_expression_ids ();
-  free_scc_vn ();
   if (!do_fre)
-    remove_dead_inserted_code ();
+    {
+      remove_dead_inserted_code ();
+      todo |= TODO_verify_flow;
+    }
 
   scev_finalize ();
   fini_pre (do_fre);
 
+  if (!do_fre)
+    /* TODO: tail_merge_optimize may merge all predecessors of a block, in which
+       case we can merge the block with the remaining predecessor of the block.
+       It should either:
+       - call merge_blocks after each tail merge iteration
+       - call merge_blocks after all tail merge iterations
+       - mark TODO_cleanup_cfg when necessary
+       - share the cfg cleanup with fini_pre.  */
+    todo |= tail_merge_optimize (todo);
+  free_scc_vn ();
+
   return todo;
 }
 
@@ -4910,7 +4969,7 @@ struct gimple_opt_pass pass_pre =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   TODO_rebuild_alias,                  /* todo_flags_start */
-  TODO_update_ssa_only_virtuals | TODO_dump_func | TODO_ggc_collect
+  TODO_update_ssa_only_virtuals  | TODO_ggc_collect
   | TODO_verify_ssa /* todo_flags_finish */
  }
 };
@@ -4945,6 +5004,6 @@ struct gimple_opt_pass pass_fre =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
+  TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
  }
 };