re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / tree-ssa-pre.c
index 7e83967b0723fc2f123517e85e57c277306ed3b5..b4e34774f183ac75d1925995ab36cf977127be94 100644 (file)
@@ -1,5 +1,5 @@
 /* SSA-PRE for trees.
-   Copyright (C) 2001-2013 Free Software Foundation, Inc.
+   Copyright (C) 2001-2015 Free Software Foundation, Inc.
    Contributed by Daniel Berlin <dan@dberlin.org> and Steven Bosscher
    <stevenb@suse.de>
 
@@ -23,26 +23,53 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
 #include "basic-block.h"
 #include "gimple-pretty-print.h"
 #include "tree-inline.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "gimple.h"
 #include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
 #include "gimple-ssa.h"
 #include "tree-cfg.h"
 #include "tree-phinodes.h"
 #include "ssa-iterators.h"
+#include "stringpool.h"
 #include "tree-ssanames.h"
 #include "tree-ssa-loop.h"
 #include "tree-into-ssa.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
-#include "hash-table.h"
 #include "tree-iterator.h"
 #include "alloc-pool.h"
 #include "obstack.h"
 #include "tree-pass.h"
-#include "flags.h"
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "tree-ssa-sccvn.h"
@@ -50,8 +77,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "dbgcnt.h"
 #include "domwalk.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
 #include "ipa-prop.h"
 #include "tree-ssa-propagate.h"
+#include "ipa-utils.h"
+#include "tree-cfgcleanup.h"
 
 /* TODO:
 
@@ -174,15 +205,13 @@ typedef union pre_expr_union_d
   vn_reference_t reference;
 } pre_expr_union;
 
-typedef struct pre_expr_d : typed_noop_remove <pre_expr_d>
+typedef struct pre_expr_d : nofree_ptr_hash <pre_expr_d>
 {
   enum pre_expr_kind kind;
   unsigned int id;
   pre_expr_union u;
 
   /* hash_table support.  */
-  typedef pre_expr_d value_type;
-  typedef pre_expr_d compare_type;
   static inline hashval_t hash (const pre_expr_d *);
   static inline int equal (const pre_expr_d *, const pre_expr_d *);
 } *pre_expr;
@@ -195,7 +224,7 @@ typedef struct pre_expr_d : typed_noop_remove <pre_expr_d>
 /* Compare E1 and E1 for equality.  */
 
 inline int
-pre_expr_d::equal (const value_type *e1, const compare_type *e2)
+pre_expr_d::equal (const pre_expr_d *e1, const pre_expr_d *e2)
 {
   if (e1->kind != e2->kind)
     return false;
@@ -220,7 +249,7 @@ pre_expr_d::equal (const value_type *e1, const compare_type *e2)
 /* Hash E.  */
 
 inline hashval_t
-pre_expr_d::hash (const value_type *e)
+pre_expr_d::hash (const pre_expr_d *e)
 {
   switch (e->kind)
     {
@@ -242,7 +271,7 @@ static unsigned int next_expression_id;
 
 /* Mapping from expression to id number we can use in bitmap sets.  */
 static vec<pre_expr> expressions;
-static hash_table <pre_expr_d> expression_to_id;
+static hash_table<pre_expr_d> *expression_to_id;
 static vec<unsigned> name_to_id;
 
 /* Allocate an expression id for EXPR.  */
@@ -259,17 +288,16 @@ alloc_expression_id (pre_expr expr)
     {
       unsigned version = SSA_NAME_VERSION (PRE_EXPR_NAME (expr));
       /* vec::safe_grow_cleared allocates no headroom.  Avoid frequent
-        re-allocations by using vec::reserve upfront.  There is no
-        vec::quick_grow_cleared unfortunately.  */
+        re-allocations by using vec::reserve upfront.  */
       unsigned old_len = name_to_id.length ();
       name_to_id.reserve (num_ssa_names - old_len);
-      name_to_id.safe_grow_cleared (num_ssa_names);
+      name_to_id.quick_grow_cleared (num_ssa_names);
       gcc_assert (name_to_id[version] == 0);
       name_to_id[version] = expr->id;
     }
   else
     {
-      slot = expression_to_id.find_slot (expr, INSERT);
+      slot = expression_to_id->find_slot (expr, INSERT);
       gcc_assert (!*slot);
       *slot = expr;
     }
@@ -298,7 +326,7 @@ lookup_expression_id (const pre_expr expr)
     }
   else
     {
-      slot = expression_to_id.find_slot (expr, NO_INSERT);
+      slot = expression_to_id->find_slot (expr, NO_INSERT);
       if (!slot)
        return 0;
       return ((pre_expr)*slot)->id;
@@ -334,7 +362,7 @@ clear_expression_ids (void)
   expressions.release ();
 }
 
-static alloc_pool pre_expr_pool;
+static pool_allocator<pre_expr_d> pre_expr_pool ("pre_expr nodes", 30);
 
 /* Given an SSA_NAME NAME, get or create a pre_expr to represent it.  */
 
@@ -352,7 +380,7 @@ get_or_alloc_expr_for_name (tree name)
   if (result_id != 0)
     return expression_for_id (result_id);
 
-  result = (pre_expr) pool_alloc (pre_expr_pool);
+  result = pre_expr_pool.allocate ();
   result->kind = NAME;
   PRE_EXPR_NAME (result) = name;
   alloc_expression_id (result);
@@ -411,13 +439,12 @@ typedef struct bb_bitmap_sets
   /* A cache for value_dies_in_block_x.  */
   bitmap expr_dies;
 
+  /* The live virtual operand on successor edges.  */
+  tree vop_on_exit;
+
   /* True if we have visited this block during ANTIC calculation.  */
   unsigned int visited : 1;
 
-  /* True we have deferred processing this block during ANTIC
-     calculation until its successor is processed.  */
-  unsigned int deferred : 1;
-
   /* True when the block contains a call that might not return.  */
   unsigned int contains_may_not_return_call : 1;
 } *bb_value_sets_t;
@@ -431,8 +458,8 @@ typedef struct bb_bitmap_sets
 #define NEW_SETS(BB)   ((bb_value_sets_t) ((BB)->aux))->new_sets
 #define EXPR_DIES(BB)  ((bb_value_sets_t) ((BB)->aux))->expr_dies
 #define BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited
-#define BB_DEFERRED(BB) ((bb_value_sets_t) ((BB)->aux))->deferred
 #define BB_MAY_NOTRETURN(BB) ((bb_value_sets_t) ((BB)->aux))->contains_may_not_return_call
+#define BB_LIVE_VOP_ON_EXIT(BB) ((bb_value_sets_t) ((BB)->aux))->vop_on_exit
 
 
 /* Basic block list in postorder.  */
@@ -474,7 +501,7 @@ static unsigned int get_expr_value_id (pre_expr);
 /* We can add and remove elements and entries to and from sets
    and hash tables, so we use alloc pools for them.  */
 
-static alloc_pool bitmap_set_pool;
+static pool_allocator<bitmap_set> bitmap_set_pool ("Bitmap sets", 30);
 static bitmap_obstack grand_bitmap_obstack;
 
 /* Set of blocks with statements that have had their EH properties changed.  */
@@ -486,7 +513,7 @@ static bitmap need_ab_cleanup;
 /* A three tuple {e, pred, v} used to cache phi translations in the
    phi_translate_table.  */
 
-typedef struct expr_pred_trans_d : typed_free_remove<expr_pred_trans_d>
+typedef struct expr_pred_trans_d : free_ptr_hash<expr_pred_trans_d>
 {
   /* The expression.  */
   pre_expr e;
@@ -502,10 +529,8 @@ typedef struct expr_pred_trans_d : typed_free_remove<expr_pred_trans_d>
   hashval_t hashcode;
 
   /* hash_table support.  */
-  typedef expr_pred_trans_d value_type;
-  typedef expr_pred_trans_d compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline int equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const expr_pred_trans_d *);
+  static inline int equal (const expr_pred_trans_d *, const expr_pred_trans_d *);
 } *expr_pred_trans_t;
 typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
 
@@ -516,8 +541,8 @@ expr_pred_trans_d::hash (const expr_pred_trans_d *e)
 }
 
 inline int
-expr_pred_trans_d::equal (const value_type *ve1,
-                         const compare_type *ve2)
+expr_pred_trans_d::equal (const expr_pred_trans_d *ve1,
+                         const expr_pred_trans_d *ve2)
 {
   basic_block b1 = ve1->pred;
   basic_block b2 = ve2->pred;
@@ -531,7 +556,7 @@ expr_pred_trans_d::equal (const value_type *ve1,
 
 /* The phi_translate_table caches phi translations for a given
    expression and predecessor.  */
-static hash_table <expr_pred_trans_d> phi_translate_table;
+static hash_table<expr_pred_trans_d> *phi_translate_table;
 
 /* Add the tuple mapping from {expression E, basic block PRED} to
    the phi translation table and return whether it pre-existed.  */
@@ -546,7 +571,7 @@ phi_trans_add (expr_pred_trans_t *entry, pre_expr e, basic_block pred)
   tem.e = e;
   tem.pred = pred;
   tem.hashcode = hash;
-  slot = phi_translate_table.find_slot_with_hash (&tem, hash, INSERT);
+  slot = phi_translate_table->find_slot_with_hash (&tem, hash, INSERT);
   if (*slot)
     {
       *entry = *slot;
@@ -590,7 +615,7 @@ add_to_value (unsigned int v, pre_expr e)
 static bitmap_set_t
 bitmap_set_new (void)
 {
-  bitmap_set_t ret = (bitmap_set_t) pool_alloc (bitmap_set_pool);
+  bitmap_set_t ret = bitmap_set_pool.allocate ();
   bitmap_initialize (&ret->expressions, &grand_bitmap_obstack);
   bitmap_initialize (&ret->values, &grand_bitmap_obstack);
   return ret;
@@ -706,8 +731,8 @@ sorted_array_from_bitmap_set (bitmap_set_t set)
   bitmap_iterator bi, bj;
   vec<pre_expr> result;
 
-  /* Pre-allocate roughly enough space for the array.  */
-  result.create (bitmap_count_bits (&set->values));
+  /* Pre-allocate enough space for the array.  */
+  result.create (bitmap_count_bits (&set->expressions));
 
   FOR_EACH_VALUE_ID_IN_SET (set, i, bi)
     {
@@ -725,7 +750,7 @@ sorted_array_from_bitmap_set (bitmap_set_t set)
       EXECUTE_IF_SET_IN_BITMAP (exprset, 0, j, bj)
        {
          if (bitmap_bit_p (&set->expressions, j))
-           result.safe_push (expression_for_id (j));
+           result.quick_push (expression_for_id (j));
         }
     }
 
@@ -1080,7 +1105,7 @@ get_or_alloc_expr_for_constant (tree constant)
   if (result_id != 0)
     return expression_for_id (result_id);
 
-  newexpr = (pre_expr) pool_alloc (pre_expr_pool);
+  newexpr = pre_expr_pool.allocate ();
   newexpr->kind = CONSTANT;
   PRE_EXPR_CONSTANT (newexpr) = constant;
   alloc_expression_id (newexpr);
@@ -1131,13 +1156,13 @@ get_or_alloc_expr_for (tree t)
       vn_nary_op_lookup (t, &result);
       if (result != NULL)
        {
-         pre_expr e = (pre_expr) pool_alloc (pre_expr_pool);
+         pre_expr e = pre_expr_pool.allocate ();
          e->kind = NARY;
          PRE_EXPR_NARY (e) = result;
          result_id = lookup_expression_id (e);
          if (result_id != 0)
            {
-             pool_free (pre_expr_pool, e);
+             pre_expr_pool.remove (e);
              e = expression_for_id (result_id);
              return e;
            }
@@ -1297,7 +1322,8 @@ translate_vuse_through_block (vec<vn_reference_op_s> operands,
          unsigned int cnt;
          /* Try to find a vuse that dominates this phi node by skipping
             non-clobbering statements.  */
-         vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false);
+         vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false,
+                                          NULL, NULL);
          if (visited)
            BITMAP_FREE (visited);
        }
@@ -1480,7 +1506,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            if (result && is_gimple_min_invariant (result))
              return get_or_alloc_expr_for_constant (result);
 
-           expr = (pre_expr) pool_alloc (pre_expr_pool);
+           expr = pre_expr_pool.allocate ();
            expr->kind = NARY;
            expr->id = 0;
            if (nary)
@@ -1522,12 +1548,11 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
        tree newvuse = vuse;
        vec<vn_reference_op_s> newoperands = vNULL;
        bool changed = false, same_valid = true;
-       unsigned int i, j, n;
+       unsigned int i, n;
        vn_reference_op_t operand;
        vn_reference_t newref;
 
-       for (i = 0, j = 0;
-            operands.iterate (i, &operand); i++, j++)
+       for (i = 0; operands.iterate (i, &operand); i++)
          {
            pre_expr opresult;
            pre_expr leader;
@@ -1571,6 +1596,8 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                newoperands.release ();
                return NULL;
              }
+           if (!changed)
+             continue;
            if (!newoperands.exists ())
              newoperands = operands.copy ();
            /* We may have changed from an SSA_NAME to a constant */
@@ -1580,36 +1607,14 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            newop.op0 = op[0];
            newop.op1 = op[1];
            newop.op2 = op[2];
-           /* If it transforms a non-constant ARRAY_REF into a constant
-              one, adjust the constant offset.  */
-           if (newop.opcode == ARRAY_REF
-               && newop.off == -1
-               && TREE_CODE (op[0]) == INTEGER_CST
-               && TREE_CODE (op[1]) == INTEGER_CST
-               && TREE_CODE (op[2]) == INTEGER_CST)
-             {
-               double_int off = tree_to_double_int (op[0]);
-               off += -tree_to_double_int (op[1]);
-               off *= tree_to_double_int (op[2]);
-               if (off.fits_shwi ())
-                 newop.off = off.low;
-             }
-           newoperands[j] = newop;
-           /* If it transforms from an SSA_NAME to an address, fold with
-              a preceding indirect reference.  */
-           if (j > 0 && op[0] && TREE_CODE (op[0]) == ADDR_EXPR
-               && newoperands[j - 1].opcode == MEM_REF)
-             vn_reference_fold_indirect (&newoperands, &j);
-         }
-       if (i != operands.length ())
-         {
-           newoperands.release ();
-           return NULL;
+           newoperands[i] = newop;
          }
+       gcc_checking_assert (i == operands.length ());
 
        if (vuse)
          {
-           newvuse = translate_vuse_through_block (newoperands,
+           newvuse = translate_vuse_through_block (newoperands.exists ()
+                                                   ? newoperands : operands,
                                                    ref->set, ref->type,
                                                    vuse, phiblock, pred,
                                                    &same_valid);
@@ -1627,7 +1632,8 @@ 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,
+                                                     newoperands.exists ()
+                                                     ? newoperands : operands,
                                                      &newref, VN_WALK);
            if (result)
              newoperands.release ();
@@ -1662,7 +1668,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                return NULL;
              }
 
-           expr = (pre_expr) pool_alloc (pre_expr_pool);
+           expr = pre_expr_pool.allocate ();
            expr->kind = REFERENCE;
            expr->id = 0;
 
@@ -1686,11 +1692,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                  }
                else
                  new_val_id = ref->value_id;
+               if (!newoperands.exists ())
+                 newoperands = operands.copy ();
                newref = vn_reference_insert_pieces (newvuse, ref->set,
                                                     ref->type,
                                                     newoperands,
                                                     result, new_val_id);
-               newoperands.create (0);
+               newoperands = vNULL;
                PRE_EXPR_REFERENCE (expr) = newref;
                constant = fully_constant_expression (expr);
                if (constant != expr)
@@ -1722,8 +1730,9 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
 
            return get_or_alloc_expr_for_name (def);
          }
-       /* Otherwise return it unchanged - it will get cleaned if its
-          value is not available in PREDs AVAIL_OUT set of expressions.  */
+       /* Otherwise return it unchanged - it will get removed if its
+          value is not available in PREDs AVAIL_OUT set of expressions
+          by the subtraction of TMP_GEN.  */
        return expr;
       }
 
@@ -1771,7 +1780,7 @@ phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
       else
        /* Remove failed translations again, they cause insert
           iteration to not pick up new opportunities reliably.  */
-       phi_translate_table.remove_elt_with_hash (slot, slot->hashcode);
+       phi_translate_table->remove_elt_with_hash (slot, slot->hashcode);
     }
 
   return phitrans;
@@ -1962,14 +1971,14 @@ op_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, tree op)
    For loads/calls, we also see if the vuse is killed in this block.  */
 
 static bool
-valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr,
-              basic_block block)
+valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr)
 {
   switch (expr->kind)
     {
     case NAME:
-      return bitmap_find_leader (AVAIL_OUT (block),
-                                get_expr_value_id (expr)) != NULL;
+      /* By construction all NAMEs are available.  Non-available
+        NAMEs are removed by subtracting TMP_GEN from the sets.  */
+      return true;
     case NARY:
       {
        unsigned int i;
@@ -2007,7 +2016,7 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr,
    PA_IN.  */
 
 static void
-dependent_clean (bitmap_set_t set1, bitmap_set_t set2, basic_block block)
+dependent_clean (bitmap_set_t set1, bitmap_set_t set2)
 {
   vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1);
   pre_expr expr;
@@ -2015,7 +2024,7 @@ dependent_clean (bitmap_set_t set1, bitmap_set_t set2, basic_block block)
 
   FOR_EACH_VEC_ELT (exprs, i, expr)
     {
-      if (!valid_in_sets (set1, set2, expr, block))
+      if (!valid_in_sets (set1, set2, expr))
        bitmap_remove_from_set (set1, expr);
     }
   exprs.release ();
@@ -2026,7 +2035,7 @@ dependent_clean (bitmap_set_t set1, bitmap_set_t set2, basic_block block)
    in SET.  */
 
 static void
-clean (bitmap_set_t set, basic_block block)
+clean (bitmap_set_t set)
 {
   vec<pre_expr> exprs = sorted_array_from_bitmap_set (set);
   pre_expr expr;
@@ -2034,7 +2043,7 @@ clean (bitmap_set_t set, basic_block block)
 
   FOR_EACH_VEC_ELT (exprs, i, expr)
     {
-      if (!valid_in_sets (set, NULL, expr, block))
+      if (!valid_in_sets (set, NULL, expr))
        bitmap_remove_from_set (set, expr);
     }
   exprs.release ();
@@ -2088,26 +2097,6 @@ static sbitmap has_abnormal_preds;
 
 static sbitmap changed_blocks;
 
-/* Decide whether to defer a block for a later iteration, or PHI
-   translate SOURCE to DEST using phis in PHIBLOCK.  Return false if we
-   should defer the block, and true if we processed it.  */
-
-static bool
-defer_or_phi_translate_block (bitmap_set_t dest, bitmap_set_t source,
-                             basic_block block, basic_block phiblock)
-{
-  if (!BB_VISITED (phiblock))
-    {
-      bitmap_set_bit (changed_blocks, block->index);
-      BB_VISITED (block) = 0;
-      BB_DEFERRED (block) = 1;
-      return false;
-    }
-  else
-    phi_translate_set (dest, source, block, phiblock);
-  return true;
-}
-
 /* Compute the ANTIC set for BLOCK.
 
    If succs(BLOCK) > 1 then
@@ -2147,41 +2136,18 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
   else if (single_succ_p (block))
     {
       basic_block succ_bb = single_succ (block);
-
-      /* We trade iterations of the dataflow equations for having to
-        phi translate the maximal set, which is incredibly slow
-        (since the maximal set often has 300+ members, even when you
-        have a small number of blocks).
-        Basically, we defer the computation of ANTIC for this block
-        until we have processed it's successor, which will inevitably
-        have a *much* smaller set of values to phi translate once
-        clean has been run on it.
-        The cost of doing this is that we technically perform more
-        iterations, however, they are lower cost iterations.
-
-        Timings for PRE on tramp3d-v4:
-        without maximal set fix: 11 seconds
-        with maximal set fix/without deferring: 26 seconds
-        with maximal set fix/with deferring: 11 seconds
-     */
-
-      if (!defer_or_phi_translate_block (ANTIC_OUT, ANTIC_IN (succ_bb),
-                                       block, succ_bb))
-       {
-         changed = true;
-         goto maybe_dump_sets;
-       }
+      gcc_assert (BB_VISITED (succ_bb));
+      phi_translate_set (ANTIC_OUT, ANTIC_IN (succ_bb), block, succ_bb);
     }
   /* If we have multiple successors, we take the intersection of all of
      them.  Note that in the case of loop exit phi nodes, we may have
      phis to translate through.  */
   else
     {
-      vec<basic_block> worklist;
       size_t i;
       basic_block bprime, first = NULL;
 
-      worklist.create (EDGE_COUNT (block->succs));
+      auto_vec<basic_block> worklist (EDGE_COUNT (block->succs));
       FOR_EACH_EDGE (e, ei, block->succs)
        {
          if (!first
@@ -2191,21 +2157,11 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
            worklist.quick_push (e->dest);
        }
 
-      /* Of multiple successors we have to have visited one already.  */
-      if (!first)
-       {
-         bitmap_set_bit (changed_blocks, block->index);
-         BB_VISITED (block) = 0;
-         BB_DEFERRED (block) = 1;
-         changed = true;
-         worklist.release ();
-         goto maybe_dump_sets;
-       }
+      /* Of multiple successors we have to have visited one already
+         which is guaranteed by iteration order.  */
+      gcc_assert (first != NULL);
 
-      if (!gimple_seq_empty_p (phi_nodes (first)))
-       phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first);
-      else
-       bitmap_set_copy (ANTIC_OUT, ANTIC_IN (first));
+      phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first);
 
       FOR_EACH_VEC_ELT (worklist, i, bprime)
        {
@@ -2219,7 +2175,6 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
          else
            bitmap_set_and (ANTIC_OUT, ANTIC_IN (bprime));
        }
-      worklist.release ();
     }
 
   /* Prune expressions that are clobbered in block and thus become
@@ -2239,7 +2194,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
     bitmap_value_insert_into_set (ANTIC_IN (block),
                                  expression_for_id (bii));
 
-  clean (ANTIC_IN (block), block);
+  clean (ANTIC_IN (block));
 
   if (!bitmap_set_equal (old, ANTIC_IN (block)))
     {
@@ -2254,23 +2209,14 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
  maybe_dump_sets:
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      if (!BB_DEFERRED (block) || BB_VISITED (block))
-       {
-         if (ANTIC_OUT)
-           print_bitmap_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index);
+      if (ANTIC_OUT)
+       print_bitmap_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index);
 
-         print_bitmap_set (dump_file, ANTIC_IN (block), "ANTIC_IN",
-                           block->index);
+      print_bitmap_set (dump_file, ANTIC_IN (block), "ANTIC_IN",
+                       block->index);
 
-         if (S)
-           print_bitmap_set (dump_file, S, "S", block->index);
-       }
-      else
-       {
-         fprintf (dump_file,
-                  "Block %d was deferred for a future iteration.\n",
-                  block->index);
-       }
+      if (S)
+       print_bitmap_set (dump_file, S, "S", block->index);
     }
   if (old)
     bitmap_set_free (old);
@@ -2341,11 +2287,10 @@ compute_partial_antic_aux (basic_block block,
      them.  */
   else
     {
-      vec<basic_block> worklist;
       size_t i;
       basic_block bprime;
 
-      worklist.create (EDGE_COUNT (block->succs));
+      auto_vec<basic_block> worklist (EDGE_COUNT (block->succs));
       FOR_EACH_EDGE (e, ei, block->succs)
        {
          if (e->flags & EDGE_DFS_BACK)
@@ -2377,7 +2322,6 @@ compute_partial_antic_aux (basic_block block,
                                                expression_for_id (i));
            }
        }
-      worklist.release ();
     }
 
   /* Prune expressions that are clobbered in block and thus become
@@ -2396,7 +2340,7 @@ compute_partial_antic_aux (basic_block block,
   /* PA_IN[block] = PA_IN[block] - ANTIC_IN[block] */
   bitmap_set_subtract_values (PA_IN (block), ANTIC_IN (block));
 
-  dependent_clean (PA_IN (block), ANTIC_IN (block), block);
+  dependent_clean (PA_IN (block), ANTIC_IN (block));
 
   if (!bitmap_set_equal (old_PA_IN, PA_IN (block)))
     {
@@ -2435,10 +2379,10 @@ compute_antic (void)
 
   /* If any predecessor edges are abnormal, we punt, so antic_in is empty.
      We pre-build the map of blocks with incoming abnormal edges here.  */
-  has_abnormal_preds = sbitmap_alloc (last_basic_block);
+  has_abnormal_preds = sbitmap_alloc (last_basic_block_for_fn (cfun));
   bitmap_clear (has_abnormal_preds);
 
-  FOR_ALL_BB (block)
+  FOR_ALL_BB_FN (block, cfun)
     {
       edge_iterator ei;
       edge e;
@@ -2454,7 +2398,6 @@ compute_antic (void)
        }
 
       BB_VISITED (block) = 0;
-      BB_DEFERRED (block) = 0;
 
       /* While we are here, give empty ANTIC_IN sets to each block.  */
       ANTIC_IN (block) = bitmap_set_new ();
@@ -2462,9 +2405,9 @@ compute_antic (void)
     }
 
   /* At the exit block we anticipate nothing.  */
-  BB_VISITED (EXIT_BLOCK_PTR) = 1;
+  BB_VISITED (EXIT_BLOCK_PTR_FOR_FN (cfun)) = 1;
 
-  changed_blocks = sbitmap_alloc (last_basic_block + 1);
+  changed_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun) + 1);
   bitmap_ones (changed_blocks);
   while (changed)
     {
@@ -2480,7 +2423,7 @@ compute_antic (void)
        {
          if (bitmap_bit_p (changed_blocks, postorder[i]))
            {
-             basic_block block = BASIC_BLOCK (postorder[i]);
+             basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
              changed |= compute_antic_aux (block,
                                            bitmap_bit_p (has_abnormal_preds,
                                                      block->index));
@@ -2509,7 +2452,7 @@ compute_antic (void)
            {
              if (bitmap_bit_p (changed_blocks, postorder[i]))
                {
-                 basic_block block = BASIC_BLOCK (postorder[i]);
+                 basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
                  changed
                    |= compute_partial_antic_aux (block,
                                                  bitmap_bit_p (has_abnormal_preds,
@@ -2573,6 +2516,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
                                   (TREE_CODE (fn) == FUNCTION_DECL
                                    ? build_fold_addr_expr (fn) : fn),
                                   nargs, args);
+       if (currop->with_bounds)
+         CALL_WITH_BOUNDS_P (folded) = true;
        free (args);
        if (sc)
          CALL_EXPR_STATIC_CHAIN (folded) = sc;
@@ -2855,7 +2800,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
   gimple_stmt_iterator gsi;
   tree exprtype = type ? type : get_expr_type (expr);
   pre_expr nameexpr;
-  gimple newstmt;
+  gassign *newstmt;
 
   switch (expr->kind)
     {
@@ -2890,12 +2835,15 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
            if (nary->opcode == POINTER_PLUS_EXPR)
              {
                if (i == 0)
-                 genop[i] = fold_convert (nary->type, genop[i]);
+                 genop[i] = gimple_convert (&forced_stmts,
+                                            nary->type, genop[i]);
                else if (i == 1)
-                 genop[i] = convert_to_ptrofftype (genop[i]);
+                 genop[i] = gimple_convert (&forced_stmts,
+                                            sizetype, genop[i]);
              }
            else
-             genop[i] = fold_convert (TREE_TYPE (nary->op[i]), genop[i]);
+             genop[i] = gimple_convert (&forced_stmts,
+                                        TREE_TYPE (nary->op[i]), genop[i]);
          }
        if (nary->opcode == CONSTRUCTOR)
          {
@@ -2937,8 +2885,10 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
      statements.
      We have to call unshare_expr because force_gimple_operand may
      modify the tree we pass to it.  */
-  folded = force_gimple_operand (unshare_expr (folded), &forced_stmts,
+  gimple_seq tem = NULL;
+  folded = force_gimple_operand (unshare_expr (folded), &tem,
                                 false, NULL);
+  gimple_seq_add_seq_without_update (&forced_stmts, tem);
 
   /* If we have any intermediate expressions to the value sets, add them
      to the value sets and chain them in the instruction stream.  */
@@ -2961,12 +2911,17 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
              bitmap_value_replace_in_set (NEW_SETS (block), nameexpr);
              bitmap_value_replace_in_set (AVAIL_OUT (block), nameexpr);
            }
+
+         gimple_set_vuse (stmt, BB_LIVE_VOP_ON_EXIT (block));
+         gimple_set_modified (stmt, true);
        }
       gimple_seq_add_seq (stmts, forced_stmts);
     }
 
   name = make_temp_ssa_name (exprtype, NULL, "pretmp");
   newstmt = gimple_build_assign (name, folded);
+  gimple_set_vuse (newstmt, BB_LIVE_VOP_ON_EXIT (block));
+  gimple_set_modified (newstmt, true);
   gimple_set_plf (newstmt, NECESSARY, false);
 
   gimple_seq_add_stmt (stmts, newstmt);
@@ -3007,66 +2962,6 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 }
 
 
-/* Returns true if we want to inhibit the insertions of PHI nodes
-   for the given EXPR for basic block BB (a member of a loop).
-   We want to do this, when we fear that the induction variable we
-   create might inhibit vectorization.  */
-
-static bool
-inhibit_phi_insertion (basic_block bb, pre_expr expr)
-{
-  vn_reference_t vr = PRE_EXPR_REFERENCE (expr);
-  vec<vn_reference_op_s> ops = vr->operands;
-  vn_reference_op_t op;
-  unsigned i;
-
-  /* If we aren't going to vectorize we don't inhibit anything.  */
-  if (!flag_tree_loop_vectorize)
-    return false;
-
-  /* Otherwise we inhibit the insertion when the address of the
-     memory reference is a simple induction variable.  In other
-     cases the vectorizer won't do anything anyway (either it's
-     loop invariant or a complicated expression).  */
-  FOR_EACH_VEC_ELT (ops, i, op)
-    {
-      switch (op->opcode)
-       {
-       case CALL_EXPR:
-         /* Calls are not a problem.  */
-         return false;
-
-       case ARRAY_REF:
-       case ARRAY_RANGE_REF:
-         if (TREE_CODE (op->op0) != SSA_NAME)
-           break;
-         /* Fallthru.  */
-       case SSA_NAME:
-         {
-           basic_block defbb = gimple_bb (SSA_NAME_DEF_STMT (op->op0));
-           affine_iv iv;
-           /* Default defs are loop invariant.  */
-           if (!defbb)
-             break;
-           /* Defined outside this loop, also loop invariant.  */
-           if (!flow_bb_inside_loop_p (bb->loop_father, defbb))
-             break;
-           /* If it's a simple induction variable inhibit insertion,
-              the vectorizer might be interested in this one.  */
-           if (simple_iv (bb->loop_father, bb->loop_father,
-                          op->op0, &iv, true))
-             return true;
-           /* No simple IV, vectorizer can't do anything, hence no
-              reason to inhibit the transformation for this operand.  */
-           break;
-         }
-       default:
-         break;
-       }
-    }
-  return false;
-}
-
 /* Insert the to-be-made-available values of expression EXPRNUM for each
    predecessor, stored in AVAIL, into the predecessors of BLOCK, and
    merge the result with a phi node, given the same value number as
@@ -3087,7 +2982,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
   edge_iterator ei;
   tree type = get_expr_type (expr);
   tree temp;
-  gimple phi;
+  gphi *phi;
 
   /* Make sure we aren't creating an induction variable.  */
   if (bb_loop_depth (block) > 0 && EDGE_COUNT (block->preds) == 2)
@@ -3100,8 +2995,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
                                                EDGE_PRED (block, 1)->src);
       /* Induction variables only have one edge inside the loop.  */
       if ((firstinsideloop ^ secondinsideloop)
-         && (expr->kind != REFERENCE
-             || inhibit_phi_insertion (block, expr)))
+         && expr->kind != REFERENCE)
        {
          if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "Skipping insertion of phi for partial redundancy: Looks like an induction variable\n");
@@ -3271,6 +3165,33 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
   bitmap_insert_into_set (NEW_SETS (block),
                          newphi);
 
+  /* If we insert a PHI node for a conversion of another PHI node
+     in the same basic-block try to preserve range information.
+     This is important so that followup loop passes receive optimal
+     number of iteration analysis results.  See PR61743.  */
+  if (expr->kind == NARY
+      && CONVERT_EXPR_CODE_P (expr->u.nary->opcode)
+      && TREE_CODE (expr->u.nary->op[0]) == SSA_NAME
+      && gimple_bb (SSA_NAME_DEF_STMT (expr->u.nary->op[0])) == block
+      && INTEGRAL_TYPE_P (type)
+      && INTEGRAL_TYPE_P (TREE_TYPE (expr->u.nary->op[0]))
+      && (TYPE_PRECISION (type)
+         >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
+      && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
+    {
+      wide_int min, max;
+      if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
+         && !wi::neg_p (min, SIGNED)
+         && !wi::neg_p (max, SIGNED))
+       /* Just handle extension and sign-changes of all-positive ranges.  */
+       set_range_info (temp,
+                       SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
+                       wide_int_storage::from (min, TYPE_PRECISION (type),
+                                               TYPE_SIGN (type)),
+                       wide_int_storage::from (max, TYPE_PRECISION (type),
+                                               TYPE_SIGN (type)));
+    }
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Created phi ");
@@ -3307,7 +3228,7 @@ do_regular_insertion (basic_block block, basic_block dom)
   bool new_stuff = false;
   vec<pre_expr> exprs;
   pre_expr expr;
-  vec<pre_expr> avail = vNULL;
+  auto_vec<pre_expr> avail;
   int i;
 
   exprs = sorted_array_from_bitmap_set (ANTIC_IN (block));
@@ -3437,8 +3358,11 @@ do_regular_insertion (basic_block block, basic_block dom)
 
              tree temp = make_temp_ssa_name (get_expr_type (expr),
                                              NULL, "pretmp");
-             gimple assign = gimple_build_assign (temp,
-                                                  edoubleprime->kind == CONSTANT ? PRE_EXPR_CONSTANT (edoubleprime) : PRE_EXPR_NAME (edoubleprime));
+             gassign *assign
+               = gimple_build_assign (temp,
+                                      edoubleprime->kind == CONSTANT ?
+                                      PRE_EXPR_CONSTANT (edoubleprime) :
+                                      PRE_EXPR_NAME (edoubleprime));
              gimple_stmt_iterator gsi = gsi_after_labels (block);
              gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
 
@@ -3457,7 +3381,6 @@ do_regular_insertion (basic_block block, basic_block dom)
     }
 
   exprs.release ();
-  avail.release ();
   return new_stuff;
 }
 
@@ -3475,7 +3398,7 @@ do_partial_partial_insertion (basic_block block, basic_block dom)
   bool new_stuff = false;
   vec<pre_expr> exprs;
   pre_expr expr;
-  vec<pre_expr> avail = vNULL;
+  auto_vec<pre_expr> avail;
   int i;
 
   exprs = sorted_array_from_bitmap_set (PA_IN (block));
@@ -3596,7 +3519,6 @@ do_partial_partial_insertion (basic_block block, basic_block dom)
     }
 
   exprs.release ();
-  avail.release ();
   return new_stuff;
 }
 
@@ -3655,7 +3577,7 @@ insert (void)
   basic_block bb;
   int num_iterations = 0;
 
-  FOR_ALL_BB (bb)
+  FOR_ALL_BB_FN (bb, cfun)
     NEW_SETS (bb) = bitmap_set_new ();
 
   while (new_stuff)
@@ -3663,12 +3585,12 @@ insert (void)
       num_iterations++;
       if (dump_file && dump_flags & TDF_DETAILS)
        fprintf (dump_file, "Starting insert iteration %d\n", num_iterations);
-      new_stuff = insert_aux (ENTRY_BLOCK_PTR);
+      new_stuff = insert_aux (ENTRY_BLOCK_PTR_FOR_FN (cfun));
 
       /* Clear the NEW sets before the next iteration.  We have already
          fully propagated its contents.  */
       if (new_stuff)
-       FOR_ALL_BB (bb)
+       FOR_ALL_BB_FN (bb, cfun)
          bitmap_set_free (NEW_SETS (bb));
     }
   statistics_histogram_event (cfun, "insert iterations", num_iterations);
@@ -3708,32 +3630,35 @@ compute_avail (void)
 
       e = get_or_alloc_expr_for_name (name);
       add_to_value (get_expr_value_id (e), e);
-      bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e);
-      bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
+      bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR_FOR_FN (cfun)), e);
+      bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
+                                   e);
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      print_bitmap_set (dump_file, TMP_GEN (ENTRY_BLOCK_PTR),
+      print_bitmap_set (dump_file, TMP_GEN (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
                        "tmp_gen", ENTRY_BLOCK);
-      print_bitmap_set (dump_file, AVAIL_OUT (ENTRY_BLOCK_PTR),
+      print_bitmap_set (dump_file, AVAIL_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
                        "avail_out", ENTRY_BLOCK);
     }
 
   /* Allocate the worklist.  */
-  worklist = XNEWVEC (basic_block, n_basic_blocks);
+  worklist = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
 
   /* Seed the algorithm by putting the dominator children of the entry
      block on the worklist.  */
-  for (son = first_dom_son (CDI_DOMINATORS, ENTRY_BLOCK_PTR);
+  for (son = first_dom_son (CDI_DOMINATORS, ENTRY_BLOCK_PTR_FOR_FN (cfun));
        son;
        son = next_dom_son (CDI_DOMINATORS, son))
     worklist[sp++] = son;
 
+  BB_LIVE_VOP_ON_EXIT (ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    = ssa_default_def (cfun, gimple_vop (cfun));
+
   /* Loop until the worklist is empty.  */
   while (sp)
     {
-      gimple_stmt_iterator gsi;
       gimple stmt;
       basic_block dom;
 
@@ -3744,17 +3669,24 @@ compute_avail (void)
         its immediate dominator.  */
       dom = get_immediate_dominator (CDI_DOMINATORS, block);
       if (dom)
-       bitmap_set_copy (AVAIL_OUT (block), AVAIL_OUT (dom));
+       {
+         bitmap_set_copy (AVAIL_OUT (block), AVAIL_OUT (dom));
+         BB_LIVE_VOP_ON_EXIT (block) = BB_LIVE_VOP_ON_EXIT (dom);
+       }
 
       /* Generate values for PHI nodes.  */
-      for (gsi = gsi_start_phis (block); !gsi_end_p (gsi); gsi_next (&gsi))
+      for (gphi_iterator gsi = gsi_start_phis (block); !gsi_end_p (gsi);
+          gsi_next (&gsi))
        {
-         tree result = gimple_phi_result (gsi_stmt (gsi));
+         tree result = gimple_phi_result (gsi.phi ());
 
          /* We have no need for virtual phis, as they don't represent
             actual computations.  */
          if (virtual_operand_p (result))
-           continue;
+           {
+             BB_LIVE_VOP_ON_EXIT (block) = result;
+             continue;
+           }
 
          pre_expr e = get_or_alloc_expr_for_name (result);
          add_to_value (get_expr_value_id (e), e);
@@ -3766,7 +3698,8 @@ compute_avail (void)
 
       /* Now compute value numbers and populate value sets with all
         the expressions computed in BLOCK.  */
-      for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi))
+      for (gimple_stmt_iterator gsi = gsi_start_bb (block); !gsi_end_p (gsi);
+          gsi_next (&gsi))
        {
          ssa_op_iter iter;
          tree op;
@@ -3798,6 +3731,9 @@ compute_avail (void)
              bitmap_value_insert_into_set (AVAIL_OUT (block), e);
            }
 
+         if (gimple_vdef (stmt))
+           BB_LIVE_VOP_ON_EXIT (block) = gimple_vdef (stmt);
+
          if (gimple_has_side_effects (stmt)
              || stmt_could_throw_p (stmt)
              || is_gimple_debug (stmt))
@@ -3819,18 +3755,14 @@ compute_avail (void)
            case GIMPLE_CALL:
              {
                vn_reference_t ref;
+               vn_reference_s ref1;
                pre_expr result = NULL;
-               vec<vn_reference_op_s> ops = vNULL;
 
                /* We can value number only calls to real functions.  */
                if (gimple_call_internal_p (stmt))
                  continue;
 
-               copy_reference_ops_from_call (stmt, &ops);
-               vn_reference_lookup_pieces (gimple_vuse (stmt), 0,
-                                           gimple_expr_type (stmt),
-                                           ops, &ref, VN_NOWALK);
-               ops.release ();
+               vn_reference_lookup_call (as_a <gcall *> (stmt), &ref, &ref1);
                if (!ref)
                  continue;
 
@@ -3843,7 +3775,7 @@ compute_avail (void)
                    || gimple_bb (SSA_NAME_DEF_STMT
                                    (gimple_vuse (stmt))) != block)
                  {
-                   result = (pre_expr) pool_alloc (pre_expr_pool);
+                   result = pre_expr_pool.allocate ();
                    result->kind = REFERENCE;
                    result->id = 0;
                    PRE_EXPR_REFERENCE (result) = ref;
@@ -3883,7 +3815,7 @@ compute_avail (void)
                          && vn_nary_may_trap (nary))
                        continue;
 
-                     result = (pre_expr) pool_alloc (pre_expr_pool);
+                     result = pre_expr_pool.allocate ();
                      result->kind = NARY;
                      result->id = 0;
                      PRE_EXPR_NARY (result) = nary;
@@ -3924,7 +3856,7 @@ compute_avail (void)
                            continue;
                        }
 
-                     result = (pre_expr) pool_alloc (pre_expr_pool);
+                     result = pre_expr_pool.allocate ();
                      result->kind = REFERENCE;
                      result->id = 0;
                      PRE_EXPR_REFERENCE (result) = ref;
@@ -3971,7 +3903,7 @@ compute_avail (void)
 
 /* Local state for the eliminate domwalk.  */
 static vec<gimple> el_to_remove;
-static vec<gimple> el_to_update;
+static vec<gimple> el_to_fixup;
 static unsigned int el_todo;
 static vec<tree> el_avail;
 static vec<tree> el_avail_stack;
@@ -4005,8 +3937,11 @@ eliminate_push_avail (tree op)
     {
       if (el_avail.length () <= SSA_NAME_VERSION (valnum))
        el_avail.safe_grow_cleared (SSA_NAME_VERSION (valnum) + 1);
+      tree pushop = op;
+      if (el_avail[SSA_NAME_VERSION (valnum)])
+       pushop = el_avail[SSA_NAME_VERSION (valnum)];
+      el_avail_stack.safe_push (pushop);
       el_avail[SSA_NAME_VERSION (valnum)] = op;
-      el_avail_stack.safe_push (op);
     }
 }
 
@@ -4027,9 +3962,9 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val)
     return NULL_TREE;
 
   tree res = make_temp_ssa_name (TREE_TYPE (val), NULL, "pretmp");
-  gimple tem = gimple_build_assign (res,
-                                   fold_build1 (TREE_CODE (expr),
-                                                TREE_TYPE (expr), leader));
+  gassign *tem = gimple_build_assign (res,
+                                     fold_build1 (TREE_CODE (expr),
+                                                  TREE_TYPE (expr), leader));
   gsi_insert_before (gsi, tem, GSI_SAME_STMT);
   VN_INFO_GET (res)->valnum = val;
 
@@ -4049,10 +3984,13 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val)
 class eliminate_dom_walker : public dom_walker
 {
 public:
-  eliminate_dom_walker (cdi_direction direction) : dom_walker (direction) {}
+  eliminate_dom_walker (cdi_direction direction, bool do_pre_)
+      : dom_walker (direction), do_pre (do_pre_) {}
 
   virtual void before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
+
+  bool do_pre;
 };
 
 /* Perform elimination for the basic-block B during the domwalk.  */
@@ -4060,117 +3998,98 @@ public:
 void
 eliminate_dom_walker::before_dom_children (basic_block b)
 {
-  gimple_stmt_iterator gsi;
-  gimple stmt;
-
   /* Mark new bb.  */
   el_avail_stack.safe_push (NULL_TREE);
 
-  for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
+  /* ???  If we do nothing for unreachable blocks then this will confuse
+     tailmerging.  Eventually we can reduce its reliance on SCCVN now
+     that we fully copy/constant-propagate (most) things.  */
+
+  for (gphi_iterator gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
     {
-      gimple stmt, phi = gsi_stmt (gsi);
-      tree sprime = NULL_TREE, res = PHI_RESULT (phi);
-      gimple_stmt_iterator gsi2;
-
-      /* We want to perform redundant PHI elimination.  Do so by
-        replacing the PHI with a single copy if possible.
-        Do not touch inserted, single-argument or virtual PHIs.  */
-      if (gimple_phi_num_args (phi) == 1
-         || virtual_operand_p (res))
-       {
-         gsi_next (&gsi);
-         continue;
-       }
+      gphi *phi = gsi.phi ();
+      tree res = PHI_RESULT (phi);
 
-      sprime = eliminate_avail (res);
-      if (!sprime
-         || sprime == res)
+      if (virtual_operand_p (res))
        {
-         eliminate_push_avail (res);
          gsi_next (&gsi);
          continue;
        }
-      else if (is_gimple_min_invariant (sprime))
-       {
-         if (!useless_type_conversion_p (TREE_TYPE (res),
-                                         TREE_TYPE (sprime)))
-           sprime = fold_convert (TREE_TYPE (res), sprime);
-       }
 
-      if (dump_file && (dump_flags & TDF_DETAILS))
+      tree sprime = eliminate_avail (res);
+      if (sprime
+         && sprime != res)
        {
-         fprintf (dump_file, "Replaced redundant PHI node defining ");
-         print_generic_expr (dump_file, res, 0);
-         fprintf (dump_file, " with ");
-         print_generic_expr (dump_file, sprime, 0);
-         fprintf (dump_file, "\n");
-       }
-
-      remove_phi_node (&gsi, false);
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "Replaced redundant PHI node defining ");
+             print_generic_expr (dump_file, res, 0);
+             fprintf (dump_file, " with ");
+             print_generic_expr (dump_file, sprime, 0);
+             fprintf (dump_file, "\n");
+           }
 
-      if (inserted_exprs
-         && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
-         && TREE_CODE (sprime) == SSA_NAME)
-       gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
-
-      if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
-       sprime = fold_convert (TREE_TYPE (res), sprime);
-      stmt = gimple_build_assign (res, sprime);
-      gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
-
-      gsi2 = gsi_after_labels (b);
-      gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
-      /* Queue the copy for eventual removal.  */
-      el_to_remove.safe_push (stmt);
-      /* If we inserted this PHI node ourself, it's not an elimination.  */
-      if (inserted_exprs
-         && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
-       pre_stats.phis--;
-      else
-       pre_stats.eliminations++;
-    }
+         /* If we inserted this PHI node ourself, it's not an elimination.  */
+         if (inserted_exprs
+             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
+           pre_stats.phis--;
+         else
+           pre_stats.eliminations++;
 
-  for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
-    {
-      tree lhs = NULL_TREE;
-      tree rhs = NULL_TREE;
+         /* If we will propagate into all uses don't bother to do
+            anything.  */
+         if (may_propagate_copy (res, sprime))
+           {
+             /* Mark the PHI for removal.  */
+             el_to_remove.safe_push (phi);
+             gsi_next (&gsi);
+             continue;
+           }
 
-      stmt = gsi_stmt (gsi);
+         remove_phi_node (&gsi, false);
 
-      if (gimple_has_lhs (stmt))
-       lhs = gimple_get_lhs (stmt);
+         if (inserted_exprs
+             && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
+             && TREE_CODE (sprime) == SSA_NAME)
+           gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
 
-      if (gimple_assign_single_p (stmt))
-       rhs = gimple_assign_rhs1 (stmt);
+         if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
+           sprime = fold_convert (TREE_TYPE (res), sprime);
+         gimple stmt = gimple_build_assign (res, sprime);
+         /* ???  It cannot yet be necessary (DOM walk).  */
+         gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
 
-      /* Lookup the RHS of the expression, see if we have an
-        available computation for it.  If so, replace the RHS with
-        the available computation.  */
-      if (gimple_has_lhs (stmt)
-         && TREE_CODE (lhs) == SSA_NAME
-         && !gimple_has_volatile_ops  (stmt))
-       {
-         tree sprime;
-         gimple orig_stmt = stmt;
+         gimple_stmt_iterator gsi2 = gsi_after_labels (b);
+         gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
+         continue;
+       }
 
-         sprime = eliminate_avail (lhs);
-         /* If there is no usable leader mark lhs as leader for its value.  */
-         if (!sprime)
-           eliminate_push_avail (lhs);
+      eliminate_push_avail (res);
+      gsi_next (&gsi);
+    }
 
+  for (gimple_stmt_iterator gsi = gsi_start_bb (b);
+       !gsi_end_p (gsi);
+       gsi_next (&gsi))
+    {
+      tree sprime = NULL_TREE;
+      gimple stmt = gsi_stmt (gsi);
+      tree lhs = gimple_get_lhs (stmt);
+      if (lhs && TREE_CODE (lhs) == SSA_NAME
+         && !gimple_has_volatile_ops (stmt)
          /* See PR43491.  Do not replace a global register variable when
             it is a the RHS of an assignment.  Do replace local register
             variables since gcc does not guarantee a local variable will
             be allocated in register.
-            Do not perform copy propagation or undo constant propagation.  */
-         if (gimple_assign_single_p (stmt)
-             && (TREE_CODE (rhs) == SSA_NAME
-                 || is_gimple_min_invariant (rhs)
-                 || (TREE_CODE (rhs) == VAR_DECL
-                     && is_global_var (rhs)
-                     && DECL_HARD_REGISTER (rhs))))
-           continue;
-
+            ???  The fix isn't effective here.  This should instead
+            be ensured by not value-numbering them the same but treating
+            them like volatiles?  */
+         && !(gimple_assign_single_p (stmt)
+              && (TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL
+                  && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))
+                  && is_global_var (gimple_assign_rhs1 (stmt)))))
+       {
+         sprime = eliminate_avail (lhs);
          if (!sprime)
            {
              /* If there is no existing usable leader but SCCVN thinks
@@ -4184,52 +4103,128 @@ eliminate_dom_walker::before_dom_children (basic_block b)
                  && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
                eliminate_push_avail (sprime);
            }
-         else if (is_gimple_min_invariant (sprime))
-           {
-             /* If there is no existing leader but SCCVN knows this
-                value is constant, use that constant.  */
-             if (!useless_type_conversion_p (TREE_TYPE (lhs),
-                                             TREE_TYPE (sprime)))
-               sprime = fold_convert (TREE_TYPE (lhs), sprime);
 
-             if (dump_file && (dump_flags & TDF_DETAILS))
+         /* If this now constitutes a copy duplicate points-to
+            and range info appropriately.  This is especially
+            important for inserted code.  See tree-ssa-copy.c
+            for similar code.  */
+         if (sprime
+             && TREE_CODE (sprime) == SSA_NAME)
+           {
+             basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
+             if (POINTER_TYPE_P (TREE_TYPE (lhs))
+                 && SSA_NAME_PTR_INFO (lhs)
+                 && !SSA_NAME_PTR_INFO (sprime))
                {
-                 fprintf (dump_file, "Replaced ");
-                 print_gimple_expr (dump_file, stmt, 0, 0);
-                 fprintf (dump_file, " with ");
-                 print_generic_expr (dump_file, sprime, 0);
-                 fprintf (dump_file, " in ");
-                 print_gimple_stmt (dump_file, stmt, 0, 0);
+                 duplicate_ssa_name_ptr_info (sprime,
+                                              SSA_NAME_PTR_INFO (lhs));
+                 if (b != sprime_b)
+                   mark_ptr_info_alignment_unknown
+                       (SSA_NAME_PTR_INFO (sprime));
                }
-             pre_stats.eliminations++;
-             propagate_tree_value_into_stmt (&gsi, sprime);
-             stmt = gsi_stmt (gsi);
-             update_stmt (stmt);
+             else if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+                      && SSA_NAME_RANGE_INFO (lhs)
+                      && !SSA_NAME_RANGE_INFO (sprime)
+                      && b == sprime_b)
+               duplicate_ssa_name_range_info (sprime,
+                                              SSA_NAME_RANGE_TYPE (lhs),
+                                              SSA_NAME_RANGE_INFO (lhs));
+           }
 
-             /* If we removed EH side-effects from the statement, clean
-                its EH information.  */
-             if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
+         /* Inhibit the use of an inserted PHI on a loop header when
+            the address of the memory reference is a simple induction
+            variable.  In other cases the vectorizer won't do anything
+            anyway (either it's loop invariant or a complicated
+            expression).  */
+         if (sprime
+             && TREE_CODE (sprime) == SSA_NAME
+             && do_pre
+             && flag_tree_loop_vectorize
+             && loop_outer (b->loop_father)
+             && has_zero_uses (sprime)
+             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))
+             && gimple_assign_load_p (stmt))
+           {
+             gimple def_stmt = SSA_NAME_DEF_STMT (sprime);
+             basic_block def_bb = gimple_bb (def_stmt);
+             if (gimple_code (def_stmt) == GIMPLE_PHI
+                 && b->loop_father->header == def_bb)
                {
-                 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");
+                 ssa_op_iter iter;
+                 tree op;
+                 bool found = false;
+                 FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
+                   {
+                     affine_iv iv;
+                     def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
+                     if (def_bb
+                         && flow_bb_inside_loop_p (b->loop_father, def_bb)
+                         && simple_iv (b->loop_father,
+                                       b->loop_father, op, &iv, true))
+                       {
+                         found = true;
+                         break;
+                       }
+                   }
+                 if (found)
+                   {
+                     if (dump_file && (dump_flags & TDF_DETAILS))
+                       {
+                         fprintf (dump_file, "Not replacing ");
+                         print_gimple_expr (dump_file, stmt, 0, 0);
+                         fprintf (dump_file, " with ");
+                         print_generic_expr (dump_file, sprime, 0);
+                         fprintf (dump_file, " which would add a loop"
+                                  " carried dependence to loop %d\n",
+                                  b->loop_father->num);
+                       }
+                     /* Don't keep sprime available.  */
+                     sprime = NULL_TREE;
+                   }
                }
-             continue;
            }
 
-         if (sprime
-             && sprime != lhs
-             && (rhs == NULL_TREE
-                 || TREE_CODE (rhs) != SSA_NAME
-                 || may_propagate_copy (rhs, sprime)))
+         if (sprime)
            {
+             /* If we can propagate the value computed for LHS into
+                all uses don't bother doing anything with this stmt.  */
+             if (may_propagate_copy (lhs, sprime))
+               {
+                 /* Mark it for removal.  */
+                 el_to_remove.safe_push (stmt);
+
+                 /* ???  Don't count copy/constant propagations.  */
+                 if (gimple_assign_single_p (stmt)
+                     && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+                         || gimple_assign_rhs1 (stmt) == sprime))
+                   continue;
+
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "Replaced ");
+                     print_gimple_expr (dump_file, stmt, 0, 0);
+                     fprintf (dump_file, " with ");
+                     print_generic_expr (dump_file, sprime, 0);
+                     fprintf (dump_file, " in all uses of ");
+                     print_gimple_stmt (dump_file, stmt, 0, 0);
+                   }
+
+                 pre_stats.eliminations++;
+                 continue;
+               }
+
+             /* If this is an assignment from our leader (which
+                happens in the case the value-number is a constant)
+                then there is nothing to do.  */
+             if (gimple_assign_single_p (stmt)
+                 && sprime == gimple_assign_rhs1 (stmt))
+               continue;
+
+             /* Else replace its RHS.  */
              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))
                {
                  fprintf (dump_file, "Replaced ");
@@ -4243,18 +4238,19 @@ eliminate_dom_walker::before_dom_children (basic_block b)
              if (TREE_CODE (sprime) == SSA_NAME)
                gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
                                NECESSARY, true);
-             /* We need to make sure the new and old types actually match,
-                which may require adding a simple cast, which fold_convert
-                will do for us.  */
-             if ((!rhs || TREE_CODE (rhs) != SSA_NAME)
-                 && !useless_type_conversion_p (gimple_expr_type (stmt),
-                                                TREE_TYPE (sprime)))
-               sprime = fold_convert (gimple_expr_type (stmt), sprime);
 
              pre_stats.eliminations++;
+             gimple orig_stmt = stmt;
+             if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                             TREE_TYPE (sprime)))
+               sprime = fold_convert (TREE_TYPE (lhs), sprime);
+             tree vdef = gimple_vdef (stmt);
+             tree vuse = gimple_vuse (stmt);
              propagate_tree_value_into_stmt (&gsi, sprime);
              stmt = gsi_stmt (gsi);
              update_stmt (stmt);
+             if (vdef != gimple_vdef (stmt))
+               VN_INFO (vdef)->valnum = vuse;
 
              /* If we removed EH side-effects from the statement, clean
                 its EH information.  */
@@ -4275,130 +4271,212 @@ eliminate_dom_walker::before_dom_children (basic_block b)
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    fprintf (dump_file, "  Removed AB side-effects.\n");
                }
+
+             continue;
            }
        }
+
       /* If the statement is a scalar store, see if the expression
-        has the same value number as its rhs.  If so, the store is
-        dead.  */
-      else if (gimple_assign_single_p (stmt)
-              && !gimple_has_volatile_ops (stmt)
-              && !is_gimple_reg (gimple_assign_lhs (stmt))
-              && (TREE_CODE (rhs) == SSA_NAME
-                  || is_gimple_min_invariant (rhs)))
-       {
-         tree val;
-         val = vn_reference_lookup (gimple_assign_lhs (stmt),
-                                    gimple_vuse (stmt), VN_WALK, NULL);
-         if (TREE_CODE (rhs) == SSA_NAME)
-           rhs = VN_INFO (rhs)->valnum;
-         if (val
-             && operand_equal_p (val, rhs, 0))
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               {
-                 fprintf (dump_file, "Deleted redundant store ");
-                 print_gimple_stmt (dump_file, stmt, 0, 0);
-               }
+         has the same value number as its rhs.  If so, the store is
+         dead.  */
+      if (gimple_assign_single_p (stmt)
+         && !gimple_has_volatile_ops (stmt)
+         && !is_gimple_reg (gimple_assign_lhs (stmt))
+         && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+             || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
+        {
+          tree val;
+         tree rhs = gimple_assign_rhs1 (stmt);
+          val = vn_reference_lookup (gimple_assign_lhs (stmt),
+                                     gimple_vuse (stmt), VN_WALK, NULL);
+          if (TREE_CODE (rhs) == SSA_NAME)
+            rhs = VN_INFO (rhs)->valnum;
+          if (val
+              && operand_equal_p (val, rhs, 0))
+            {
+              if (dump_file && (dump_flags & TDF_DETAILS))
+                {
+                  fprintf (dump_file, "Deleted redundant store ");
+                  print_gimple_stmt (dump_file, stmt, 0, 0);
+                }
+
+              /* Queue stmt for removal.  */
+              el_to_remove.safe_push (stmt);
+             continue;
+            }
+        }
 
-             /* Queue stmt for removal.  */
-             el_to_remove.safe_push (stmt);
-           }
-       }
-      /* Visit COND_EXPRs and fold the comparison with the
-        available value-numbers.  */
-      else if (gimple_code (stmt) == GIMPLE_COND)
+      bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt);
+      bool was_noreturn = (is_gimple_call (stmt)
+                          && gimple_call_noreturn_p (stmt));
+      tree vdef = gimple_vdef (stmt);
+      tree vuse = gimple_vuse (stmt);
+
+      /* If we didn't replace the whole stmt (or propagate the result
+         into all uses), replace all uses on this stmt with their
+        leaders.  */
+      use_operand_p use_p;
+      ssa_op_iter iter;
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
        {
-         tree op0 = gimple_cond_lhs (stmt);
-         tree op1 = gimple_cond_rhs (stmt);
-         tree result;
-
-         if (TREE_CODE (op0) == SSA_NAME)
-           op0 = VN_INFO (op0)->valnum;
-         if (TREE_CODE (op1) == SSA_NAME)
-           op1 = VN_INFO (op1)->valnum;
-         result = fold_binary (gimple_cond_code (stmt), boolean_type_node,
-                               op0, op1);
-         if (result && TREE_CODE (result) == INTEGER_CST)
+         tree use = USE_FROM_PTR (use_p);
+         /* ???  The call code above leaves stmt operands un-updated.  */
+         if (TREE_CODE (use) != SSA_NAME)
+           continue;
+         tree sprime = eliminate_avail (use);
+         if (sprime && sprime != use
+             && may_propagate_copy (use, sprime)
+             /* We substitute into debug stmts to avoid excessive
+                debug temporaries created by removed stmts, but we need
+                to avoid doing so for inserted sprimes as we never want
+                to create debug temporaries for them.  */
+             && (!inserted_exprs
+                 || TREE_CODE (sprime) != SSA_NAME
+                 || !is_gimple_debug (stmt)
+                 || !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
            {
-             if (integer_zerop (result))
-               gimple_cond_make_false (stmt);
-             else
-               gimple_cond_make_true (stmt);
-             update_stmt (stmt);
-             el_todo = TODO_cleanup_cfg;
+             propagate_value (use_p, sprime);
+             gimple_set_modified (stmt, true);
+             if (TREE_CODE (sprime) == SSA_NAME
+                 && !is_gimple_debug (stmt))
+               gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
+                               NECESSARY, true);
            }
        }
+
       /* Visit indirect calls and turn them into direct calls if
-        possible.  */
-      if (is_gimple_call (stmt))
+        possible using the devirtualization machinery.  */
+      if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
        {
-         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)
+         tree fn = gimple_call_fn (call_stmt);
+         if (fn
+             && flag_devirtualize
+             && virtual_method_call_p (fn))
            {
-             fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
-             if (!gimple_call_addr_fndecl (fn))
+             tree otr_type = obj_type_ref_class (fn);
+             tree instance;
+             ipa_polymorphic_call_context context (current_function_decl, fn, stmt, &instance);
+             bool final;
+
+             context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
+
+             vec <cgraph_node *>targets
+               = possible_polymorphic_call_targets (obj_type_ref_class (fn),
+                                                    tree_to_uhwi
+                                                      (OBJ_TYPE_REF_TOKEN (fn)),
+                                                    context,
+                                                    &final);
+             if (dump_file)
+               dump_possible_polymorphic_call_targets (dump_file, 
+                                                       obj_type_ref_class (fn),
+                                                       tree_to_uhwi
+                                                         (OBJ_TYPE_REF_TOKEN (fn)),
+                                                       context);
+             if (final && targets.length () <= 1 && dbg_cnt (devirt))
                {
-                 fn = ipa_intraprocedural_devirtualization (stmt);
-                 if (fn)
-                   fn = build_fold_addr_expr (fn);
+                 tree fn;
+                 if (targets.length () == 1)
+                   fn = targets[0]->decl;
+                 else
+                   fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+                 if (dump_enabled_p ())
+                   {
+                     location_t loc = gimple_location_safe (stmt);
+                     dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+                                      "converting indirect call to "
+                                      "function %s\n",
+                                      cgraph_node::get (fn)->name ());
+                   }
+                 gimple_call_set_fndecl (call_stmt, fn);
+                 maybe_remove_unused_call_args (cfun, call_stmt);
+                 gimple_set_modified (stmt, true);
                }
            }
-         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 ");
-                 print_generic_expr (dump_file, fn, 0);
-                 fprintf (dump_file, " in ");
-                 print_gimple_stmt (dump_file, stmt, 0, 0);
-               }
-
-             gimple_call_set_fn (stmt, fn);
-             el_to_update.safe_push (stmt);
+       }
 
+      if (gimple_modified_p (stmt))
+       {
+         /* If a formerly non-invariant ADDR_EXPR is turned into an
+            invariant one it was on a separate stmt.  */
+         if (gimple_assign_single_p (stmt)
+             && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
+           recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
+         gimple old_stmt = stmt;
+         if (is_gimple_call (stmt))
+           {
+             /* ???  Only fold calls inplace for now, this may create new
+                SSA names which in turn will confuse free_scc_vn SSA name
+                release code.  */
+             fold_stmt_inplace (&gsi);
              /* 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))
+               el_to_fixup.safe_push  (stmt);
+           }
+         else
+           {
+             fold_stmt (&gsi);
+             stmt = gsi_stmt (gsi);
+             if ((gimple_code (stmt) == GIMPLE_COND
+                  && (gimple_cond_true_p (as_a <gcond *> (stmt))
+                      || gimple_cond_false_p (as_a <gcond *> (stmt))))
+                 || (gimple_code (stmt) == GIMPLE_SWITCH
+                     && TREE_CODE (gimple_switch_index (
+                                     as_a <gswitch *> (stmt)))
+                        == INTEGER_CST))
                el_todo |= TODO_cleanup_cfg;
+           }
+         /* If we removed EH side-effects from the statement, clean
+            its EH information.  */
+         if (maybe_clean_or_replace_eh_stmt (old_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");
+           }
+         /* 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");
+           }
+         update_stmt (stmt);
+         if (vdef != gimple_vdef (stmt))
+           VN_INFO (vdef)->valnum = vuse;
+       }
 
-             /* 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");
-               }
-
-             /* 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");
-               }
+      /* Make new values available - for fully redundant LHS we
+         continue with the next stmt above and skip this.  */
+      def_operand_p defp;
+      FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF)
+       eliminate_push_avail (DEF_FROM_PTR (defp));
+    }
 
-             /* Changing an indirect call to a direct call may
-                have exposed different semantics.  This may
-                require an SSA update.  */
-             el_todo |= TODO_update_ssa_only_virtuals;
+  /* Replace destination PHI arguments.  */
+  edge_iterator ei;
+  edge e;
+  FOR_EACH_EDGE (e, ei, b->succs)
+    {
+      for (gphi_iterator gsi = gsi_start_phis (e->dest);
+          !gsi_end_p (gsi);
+          gsi_next (&gsi))
+       {
+         gphi *phi = gsi.phi ();
+         use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
+         tree arg = USE_FROM_PTR (use_p);
+         if (TREE_CODE (arg) != SSA_NAME
+             || virtual_operand_p (arg))
+           continue;
+         tree sprime = eliminate_avail (arg);
+         if (sprime && may_propagate_copy (arg, sprime))
+           {
+             propagate_value (use_p, sprime);
+             if (TREE_CODE (sprime) == SSA_NAME)
+               gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
            }
        }
     }
@@ -4411,80 +4489,98 @@ eliminate_dom_walker::after_dom_children (basic_block)
 {
   tree entry;
   while ((entry = el_avail_stack.pop ()) != NULL_TREE)
-    el_avail[SSA_NAME_VERSION (VN_INFO (entry)->valnum)] = NULL_TREE;
+    {
+      tree valnum = VN_INFO (entry)->valnum;
+      tree old = el_avail[SSA_NAME_VERSION (valnum)];
+      if (old == entry)
+       el_avail[SSA_NAME_VERSION (valnum)] = NULL_TREE;
+      else
+       el_avail[SSA_NAME_VERSION (valnum)] = entry;
+    }
 }
 
 /* Eliminate fully redundant computations.  */
 
 static unsigned int
-eliminate (void)
+eliminate (bool do_pre)
 {
   gimple_stmt_iterator gsi;
   gimple stmt;
-  unsigned i;
 
   need_eh_cleanup = BITMAP_ALLOC (NULL);
   need_ab_cleanup = BITMAP_ALLOC (NULL);
 
   el_to_remove.create (0);
-  el_to_update.create (0);
+  el_to_fixup.create (0);
   el_todo = 0;
-  el_avail.create (0);
+  el_avail.create (num_ssa_names);
   el_avail_stack.create (0);
 
-  eliminate_dom_walker (CDI_DOMINATORS).walk (cfun->cfg->x_entry_block_ptr);
+  eliminate_dom_walker (CDI_DOMINATORS,
+                       do_pre).walk (cfun->cfg->x_entry_block_ptr);
 
   el_avail.release ();
   el_avail_stack.release ();
 
   /* We cannot remove stmts during BB walk, especially not release SSA
      names there as this confuses the VN machinery.  The stmts ending
-     up in el_to_remove are either stores or simple copies.  */
-  FOR_EACH_VEC_ELT (el_to_remove, i, stmt)
+     up in el_to_remove are either stores or simple copies.
+     Remove stmts in reverse order to make debug stmt creation possible.  */
+  while (!el_to_remove.is_empty ())
     {
-      tree lhs = gimple_assign_lhs (stmt);
-      tree rhs = gimple_assign_rhs1 (stmt);
-      use_operand_p use_p;
-      gimple use_stmt;
-
-      /* If there is a single use only, propagate the equivalency
-        instead of keeping the copy.  */
-      if (TREE_CODE (lhs) == SSA_NAME
-         && TREE_CODE (rhs) == SSA_NAME
-         && single_imm_use (lhs, &use_p, &use_stmt)
-         && may_propagate_copy (USE_FROM_PTR (use_p), rhs))
+      stmt = el_to_remove.pop ();
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
-         SET_USE (use_p, rhs);
-         update_stmt (use_stmt);
-         if (inserted_exprs
-             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs))
-             && TREE_CODE (rhs) == SSA_NAME)
-           gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true);
+         fprintf (dump_file, "Removing dead stmt ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
        }
 
-      /* If this is a store or a now unused copy, remove it.  */
-      if (TREE_CODE (lhs) != SSA_NAME
-         || has_zero_uses (lhs))
+      tree lhs;
+      if (gimple_code (stmt) == GIMPLE_PHI)
+       lhs = gimple_phi_result (stmt);
+      else
+       lhs = gimple_get_lhs (stmt);
+
+      if (inserted_exprs
+         && TREE_CODE (lhs) == SSA_NAME)
+       bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
+
+      gsi = gsi_for_stmt (stmt);
+      if (gimple_code (stmt) == GIMPLE_PHI)
+       remove_phi_node (&gsi, true);
+      else
        {
          basic_block bb = gimple_bb (stmt);
-         gsi = gsi_for_stmt (stmt);
          unlink_stmt_vdef (stmt);
          if (gsi_remove (&gsi, true))
            bitmap_set_bit (need_eh_cleanup, bb->index);
-         if (inserted_exprs
-             && TREE_CODE (lhs) == SSA_NAME)
-           bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
          release_defs (stmt);
        }
+
+      /* Removing a stmt may expose a forwarder block.  */
+      el_todo |= TODO_cleanup_cfg;
     }
   el_to_remove.release ();
 
-  /* 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 (el_to_update, i, stmt)
-    update_stmt (stmt);
-  el_to_update.release ();
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!el_to_fixup.is_empty ())
+    {
+      stmt = el_to_fixup.pop ();
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+       }
+
+      if (fixup_noreturn_call (stmt))
+       el_todo |= TODO_cleanup_cfg;
+    }
+  el_to_fixup.release ();
 
   return el_todo;
 }
@@ -4652,7 +4748,7 @@ init_pre (void)
   connect_infinite_loops_to_exit ();
   memset (&pre_stats, 0, sizeof (pre_stats));
 
-  postorder = XNEWVEC (int, n_basic_blocks);
+  postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
   postorder_num = inverted_post_order_compute (postorder);
 
   alloc_aux_for_blocks (sizeof (struct bb_bitmap_sets));
@@ -4661,13 +4757,9 @@ init_pre (void)
   calculate_dominance_info (CDI_DOMINATORS);
 
   bitmap_obstack_initialize (&grand_bitmap_obstack);
-  phi_translate_table.create (5110);
-  expression_to_id.create (num_ssa_names * 3);
-  bitmap_set_pool = create_alloc_pool ("Bitmap sets",
-                                      sizeof (struct bitmap_set), 30);
-  pre_expr_pool = create_alloc_pool ("pre_expr nodes",
-                                    sizeof (struct pre_expr_d), 30);
-  FOR_ALL_BB (bb)
+  phi_translate_table = new hash_table<expr_pred_trans_d> (5110);
+  expression_to_id = new hash_table<pre_expr_d> (num_ssa_names * 3);
+  FOR_ALL_BB_FN (bb, cfun)
     {
       EXP_GEN (bb) = bitmap_set_new ();
       PHI_GEN (bb) = bitmap_set_new ();
@@ -4686,10 +4778,12 @@ fini_pre ()
   value_expressions.release ();
   BITMAP_FREE (inserted_exprs);
   bitmap_obstack_release (&grand_bitmap_obstack);
-  free_alloc_pool (bitmap_set_pool);
-  free_alloc_pool (pre_expr_pool);
-  phi_translate_table.dispose ();
-  expression_to_id.dispose ();
+  bitmap_set_pool.release ();
+  pre_expr_pool.release ();
+  delete phi_translate_table;
+  phi_translate_table = NULL;
+  delete expression_to_id;
+  expression_to_id = NULL;
   name_to_id.release ();
 
   free_aux_for_blocks ();
@@ -4697,15 +4791,43 @@ fini_pre ()
   free_dominance_info (CDI_POST_DOMINATORS);
 }
 
-/* Gate and execute functions for PRE.  */
+namespace {
 
-static unsigned int
-do_pre (void)
+const pass_data pass_data_pre =
+{
+  GIMPLE_PASS, /* type */
+  "pre", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_PRE, /* tv_id */
+  /* PROP_no_crit_edges is ensured by placing pass_split_crit_edges before
+     pass_pre.  */
+  ( PROP_no_crit_edges | PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  PROP_no_crit_edges, /* properties_destroyed */
+  TODO_rebuild_alias, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_pre : public gimple_opt_pass
+{
+public:
+  pass_pre (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_pre, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return flag_tree_pre != 0; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_pre
+
+unsigned int
+pass_pre::execute (function *fun)
 {
   unsigned int todo = 0;
 
   do_partial_partial =
-    flag_tree_partial_pre && optimize_function_for_speed_p (cfun);
+    flag_tree_partial_pre && optimize_function_for_speed_p (fun);
 
   /* This has to happen before SCCVN runs because
      loop_optimizer_init may create new phis, etc.  */
@@ -4728,7 +4850,7 @@ do_pre (void)
      fixed, don't run it when he have an incredibly large number of
      bb's.  If we aren't going to run insert, there is no point in
      computing ANTIC, either, even though it's plenty fast.  */
-  if (n_basic_blocks < 4000)
+  if (n_basic_blocks_for_fn (fun) < 4000)
     {
       compute_antic ();
       insert ();
@@ -4740,17 +4862,20 @@ do_pre (void)
   remove_fake_exit_edges ();
   gsi_commit_edge_inserts ();
 
+  /* Eliminate folds statements which might (should not...) end up
+     not keeping virtual operands up-to-date.  */
+  gcc_assert (!need_ssa_update_p (fun));
+
   /* Remove all the redundant expressions.  */
-  todo |= eliminate ();
+  todo |= eliminate (true);
 
-  statistics_counter_event (cfun, "Insertions", pre_stats.insertions);
-  statistics_counter_event (cfun, "PA inserted", pre_stats.pa_insert);
-  statistics_counter_event (cfun, "New PHIs", pre_stats.phis);
-  statistics_counter_event (cfun, "Eliminated", pre_stats.eliminations);
+  statistics_counter_event (fun, "Insertions", pre_stats.insertions);
+  statistics_counter_event (fun, "PA inserted", pre_stats.pa_insert);
+  statistics_counter_event (fun, "New PHIs", pre_stats.phis);
+  statistics_counter_event (fun, "Eliminated", pre_stats.eliminations);
 
   clear_expression_ids ();
   remove_dead_inserted_code ();
-  todo |= TODO_verify_flow;
 
   scev_finalize ();
   fini_pre ();
@@ -4778,55 +4903,45 @@ do_pre (void)
   return todo;
 }
 
-static bool
-gate_pre (void)
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_pre (gcc::context *ctxt)
 {
-  return flag_tree_pre != 0;
+  return new pass_pre (ctxt);
 }
 
 namespace {
 
-const pass_data pass_data_pre =
+const pass_data pass_data_fre =
 {
   GIMPLE_PASS, /* type */
-  "pre", /* name */
+  "fre", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
-  TV_TREE_PRE, /* tv_id */
-  ( PROP_no_crit_edges | PROP_cfg | PROP_ssa ), /* properties_required */
+  TV_TREE_FRE, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
-  TODO_rebuild_alias, /* todo_flags_start */
-  TODO_verify_ssa, /* todo_flags_finish */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
-class pass_pre : public gimple_opt_pass
+class pass_fre : public gimple_opt_pass
 {
 public:
-  pass_pre (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_pre, ctxt)
+  pass_fre (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_fre, ctxt)
   {}
 
   /* opt_pass methods: */
-  bool gate () { return gate_pre (); }
-  unsigned int execute () { return do_pre (); }
-
-}; // class pass_pre
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_pre (gcc::context *ctxt)
-{
-  return new pass_pre (ctxt);
-}
-
+  opt_pass * clone () { return new pass_fre (m_ctxt); }
+  virtual bool gate (function *) { return flag_tree_fre != 0; }
+  virtual unsigned int execute (function *);
 
-/* Gate and execute functions for FRE.  */
+}; // class pass_fre
 
-static unsigned int
-execute_fre (void)
+unsigned int
+pass_fre::execute (function *fun)
 {
   unsigned int todo = 0;
 
@@ -4836,55 +4951,18 @@ execute_fre (void)
   memset (&pre_stats, 0, sizeof (pre_stats));
 
   /* Remove all the redundant expressions.  */
-  todo |= eliminate ();
+  todo |= eliminate (false);
 
   todo |= fini_eliminate ();
 
   free_scc_vn ();
 
-  statistics_counter_event (cfun, "Insertions", pre_stats.insertions);
-  statistics_counter_event (cfun, "Eliminated", pre_stats.eliminations);
+  statistics_counter_event (fun, "Insertions", pre_stats.insertions);
+  statistics_counter_event (fun, "Eliminated", pre_stats.eliminations);
 
   return todo;
 }
 
-static bool
-gate_fre (void)
-{
-  return flag_tree_fre != 0;
-}
-
-namespace {
-
-const pass_data pass_data_fre =
-{
-  GIMPLE_PASS, /* type */
-  "fre", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
-  TV_TREE_FRE, /* tv_id */
-  ( PROP_cfg | PROP_ssa ), /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  TODO_verify_ssa, /* todo_flags_finish */
-};
-
-class pass_fre : public gimple_opt_pass
-{
-public:
-  pass_fre (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_fre, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  opt_pass * clone () { return new pass_fre (m_ctxt); }
-  bool gate () { return gate_fre (); }
-  unsigned int execute () { return execute_fre (); }
-
-}; // class pass_fre
-
 } // anon namespace
 
 gimple_opt_pass *