diff gcc/tree-ssa-pre.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/tree-ssa-pre.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/tree-ssa-pre.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,6 +1,5 @@
-/* SSA-PRE for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+/* Full and partial redundancy elimination and code hoisting on SSA GIMPLE.
+   Copyright (C) 2001-2017 Free Software Foundation, Inc.
    Contributed by Daniel Berlin <dan@dberlin.org> and Steven Bosscher
    <stevenb@suse.de>
 
@@ -23,36 +22,62 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "rtl.h"
 #include "tree.h"
-#include "basic-block.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
-#include "tree-inline.h"
-#include "tree-flow.h"
 #include "gimple.h"
-#include "tree-dump.h"
-#include "timevar.h"
-#include "fibheap.h"
-#include "hashtab.h"
-#include "tree-iterator.h"
+#include "predict.h"
 #include "alloc-pool.h"
-#include "obstack.h"
 #include "tree-pass.h"
-#include "flags.h"
-#include "bitmap.h"
-#include "langhooks.h"
+#include "ssa.h"
+#include "cgraph.h"
+#include "gimple-pretty-print.h"
+#include "fold-const.h"
+#include "cfganal.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "tree-cfg.h"
+#include "tree-into-ssa.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 #include "cfgloop.h"
 #include "tree-ssa-sccvn.h"
 #include "tree-scalar-evolution.h"
 #include "params.h"
 #include "dbgcnt.h"
+#include "domwalk.h"
+#include "tree-ssa-propagate.h"
+#include "tree-cfgcleanup.h"
+#include "alias.h"
+
+/* Even though this file is called tree-ssa-pre.c, we actually
+   implement a bit more than just PRE here.  All of them piggy-back
+   on GVN which is implemented in tree-ssa-sccvn.c.
+
+     1. Full Redundancy Elimination (FRE)
+	This is the elimination phase of GVN.
+
+     2. Partial Redundancy Elimination (PRE)
+	This is adds computation of AVAIL_OUT and ANTIC_IN and
+	doing expression insertion to form GVN-PRE.
+
+     3. Code hoisting
+	This optimization uses the ANTIC_IN sets computed for PRE
+	to move expressions further up than PRE would do, to make
+	multiple computations of the same value fully redundant.
+	This pass is explained below (after the explanation of the
+	basic algorithm for PRE).
+*/
 
 /* TODO:
 
    1. Avail sets can be shared by making an avail_find_leader that
       walks up the dominator tree and looks in those avail sets.
       This might affect code optimality, it's unclear right now.
+      Currently the AVAIL_OUT sets are the remaining quadraticness in
+      memory of GVN-PRE.
    2. Strength reduction can be performed by anticipating expressions
       we can repair later on.
    3. We can do back-substitution or smarter value numbering to catch
@@ -64,7 +89,7 @@
    represent the actual statement containing the expressions we care about,
    and we cache the value number by putting it in the expression.  */
 
-/* Basic algorithm
+/* Basic algorithm for Partial Redundancy Elimination:
 
    First we walk the statements to generate the AVAIL sets, the
    EXP_GEN sets, and the tmp_gen sets.  EXP_GEN sets represent the
@@ -104,17 +129,75 @@
    In order to make it fully redundant, we insert the expression into
    the predecessors where it is not available, but is ANTIC.
 
+   When optimizing for size, we only eliminate the partial redundancy
+   if we need to insert in only one predecessor.  This avoids almost
+   completely the code size increase that PRE usually causes.
+
    For the partial anticipation case, we only perform insertion if it
    is partially anticipated in some block, and fully available in all
    of the predecessors.
 
-   insert/insert_aux/do_regular_insertion/do_partial_partial_insertion
-   performs these steps.
+   do_pre_regular_insertion/do_pre_partial_partial_insertion
+   performs these steps, driven by insert/insert_aux.
 
    Fourth, we eliminate fully redundant expressions.
    This is a simple statement walk that replaces redundant
    calculations with the now available values.  */
 
+/* Basic algorithm for Code Hoisting:
+
+   Code hoisting is: Moving value computations up in the control flow
+   graph to make multiple copies redundant.  Typically this is a size
+   optimization, but there are cases where it also is helpful for speed.
+
+   A simple code hoisting algorithm is implemented that piggy-backs on
+   the PRE infrastructure.  For code hoisting, we have to know ANTIC_OUT
+   which is effectively ANTIC_IN - AVAIL_OUT.  The latter two have to be
+   computed for PRE, and we can use them to perform a limited version of
+   code hoisting, too.
+
+   For the purpose of this implementation, a value is hoistable to a basic
+   block B if the following properties are met:
+
+   1. The value is in ANTIC_IN(B) -- the value will be computed on all
+      paths from B to function exit and it can be computed in B);
+
+   2. The value is not in AVAIL_OUT(B) -- there would be no need to
+      compute the value again and make it available twice;
+
+   3. All successors of B are dominated by B -- makes sure that inserting
+      a computation of the value in B will make the remaining
+      computations fully redundant;
+
+   4. At least one successor has the value in AVAIL_OUT -- to avoid
+      hoisting values up too far;
+
+   5. There are at least two successors of B -- hoisting in straight
+      line code is pointless.
+
+   The third condition is not strictly necessary, but it would complicate
+   the hoisting pass a lot.  In fact, I don't know of any code hoisting
+   algorithm that does not have this requirement.  Fortunately, experiments
+   have show that most candidate hoistable values are in regions that meet
+   this condition (e.g. diamond-shape regions).
+
+   The forth condition is necessary to avoid hoisting things up too far
+   away from the uses of the value.  Nothing else limits the algorithm
+   from hoisting everything up as far as ANTIC_IN allows.  Experiments
+   with SPEC and CSiBE have shown that hoisting up too far results in more
+   spilling, less benefits for code size, and worse benchmark scores.
+   Fortunately, in practice most of the interesting hoisting opportunities
+   are caught despite this limitation.
+
+   For hoistable values that meet all conditions, expressions are inserted
+   to make the calculation of the hoistable value fully redundant.  We
+   perform code hoisting insertions after each round of PRE insertions,
+   because code hoisting never exposes new PRE opportunities, but PRE can
+   create new code hoisting opportunities.
+
+   The code hoisting algorithm is implemented in do_hoist_insert, driven
+   by insert/insert_aux.  */
+
 /* Representations of value numbers:
 
    Value numbers are represented by a representative SSA_NAME.  We
@@ -161,19 +244,23 @@
     CONSTANT
 };
 
-typedef union pre_expr_union_d
+union pre_expr_union
 {
   tree name;
   tree constant;
   vn_nary_op_t nary;
   vn_reference_t reference;
-} pre_expr_union;
-
-typedef struct 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.  */
+  static inline hashval_t hash (const pre_expr_d *);
+  static inline int equal (const pre_expr_d *, const pre_expr_d *);
 } *pre_expr;
 
 #define PRE_EXPR_NAME(e) (e)->u.name
@@ -181,12 +268,11 @@
 #define PRE_EXPR_REFERENCE(e) (e)->u.reference
 #define PRE_EXPR_CONSTANT(e) (e)->u.constant
 
-static int
-pre_expr_eq (const void *p1, const void *p2)
+/* Compare E1 and E1 for equality.  */
+
+inline int
+pre_expr_d::equal (const pre_expr_d *e1, const pre_expr_d *e2)
 {
-  const struct pre_expr_d *e1 = (const struct pre_expr_d *) p1;
-  const struct pre_expr_d *e2 = (const struct pre_expr_d *) p2;
-
   if (e1->kind != e2->kind)
     return false;
 
@@ -207,10 +293,11 @@
     }
 }
 
-static hashval_t
-pre_expr_hash (const void *p1)
+/* Hash E.  */
+
+inline hashval_t
+pre_expr_d::hash (const pre_expr_d *e)
 {
-  const struct pre_expr_d *e = (const struct pre_expr_d *) p1;
   switch (e->kind)
     {
     case CONSTANT:
@@ -226,41 +313,38 @@
     }
 }
 
-
 /* Next global expression id number.  */
 static unsigned int next_expression_id;
 
 /* Mapping from expression to id number we can use in bitmap sets.  */
-DEF_VEC_P (pre_expr);
-DEF_VEC_ALLOC_P (pre_expr, heap);
-static VEC(pre_expr, heap) *expressions;
-static htab_t expression_to_id;
-static VEC(unsigned, heap) *name_to_id;
+static vec<pre_expr> expressions;
+static hash_table<pre_expr_d> *expression_to_id;
+static vec<unsigned> name_to_id;
 
 /* Allocate an expression id for EXPR.  */
 
 static inline unsigned int
 alloc_expression_id (pre_expr expr)
 {
-  void **slot;
+  struct pre_expr_d **slot;
   /* Make sure we won't overflow. */
   gcc_assert (next_expression_id + 1 > next_expression_id);
   expr->id = next_expression_id++;
-  VEC_safe_push (pre_expr, heap, expressions, expr);
+  expressions.safe_push (expr);
   if (expr->kind == NAME)
     {
       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.  */
-      VEC_reserve (unsigned, heap, name_to_id, num_ssa_names);
-      VEC_safe_grow_cleared (unsigned, heap, name_to_id, num_ssa_names);
-      gcc_assert (VEC_index (unsigned, name_to_id, version) == 0);
-      VEC_replace (unsigned, name_to_id, version, expr->id);
+      /* vec::safe_grow_cleared allocates no headroom.  Avoid frequent
+	 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.quick_grow_cleared (num_ssa_names);
+      gcc_assert (name_to_id[version] == 0);
+      name_to_id[version] = expr->id;
     }
   else
     {
-      slot = htab_find_slot (expression_to_id, expr, INSERT);
+      slot = expression_to_id->find_slot (expr, INSERT);
       gcc_assert (!*slot);
       *slot = expr;
     }
@@ -278,18 +362,18 @@
 static inline unsigned int
 lookup_expression_id (const pre_expr expr)
 {
-  void **slot;
+  struct pre_expr_d **slot;
 
   if (expr->kind == NAME)
     {
       unsigned version = SSA_NAME_VERSION (PRE_EXPR_NAME (expr));
-      if (VEC_length (unsigned, name_to_id) <= version)
+      if (name_to_id.length () <= version)
 	return 0;
-      return VEC_index (unsigned, name_to_id, version);
+      return name_to_id[version];
     }
   else
     {
-      slot = htab_find_slot (expression_to_id, expr, NO_INSERT);
+      slot = expression_to_id->find_slot (expr, NO_INSERT);
       if (!slot)
 	return 0;
       return ((pre_expr)*slot)->id;
@@ -313,7 +397,7 @@
 static inline pre_expr
 expression_for_id (unsigned int id)
 {
-  return VEC_index (pre_expr, expressions, id);
+  return expressions[id];
 }
 
 /* Free the expression id field in all of our expressions,
@@ -322,10 +406,10 @@
 static void
 clear_expression_ids (void)
 {
-  VEC_free (pre_expr, heap, expressions);
+  expressions.release ();
 }
 
-static alloc_pool pre_expr_pool;
+static object_allocator<pre_expr_d> pre_expr_pool ("pre_expr nodes");
 
 /* Given an SSA_NAME NAME, get or create a pre_expr to represent it.  */
 
@@ -343,15 +427,13 @@
   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);
   return result;
 }
 
-static bool in_fre = false;
-
 /* An unordered bitmap set.  One bitmap tracks values, the other,
    expressions.  */
 typedef struct bitmap_set
@@ -361,15 +443,13 @@
 } *bitmap_set_t;
 
 #define FOR_EACH_EXPR_ID_IN_SET(set, id, bi)		\
-  EXECUTE_IF_SET_IN_BITMAP(&(set)->expressions, 0, (id), (bi))
+  EXECUTE_IF_SET_IN_BITMAP (&(set)->expressions, 0, (id), (bi))
 
 #define FOR_EACH_VALUE_ID_IN_SET(set, id, bi)		\
-  EXECUTE_IF_SET_IN_BITMAP(&(set)->values, 0, (id), (bi))
+  EXECUTE_IF_SET_IN_BITMAP (&(set)->values, 0, (id), (bi))
 
 /* Mapping from value id to expressions with that value_id.  */
-DEF_VEC_P (bitmap_set_t);
-DEF_VEC_ALLOC_P (bitmap_set_t, heap);
-static VEC(bitmap_set_t, heap) *value_expressions;
+static vec<bitmap> value_expressions;
 
 /* Sets that we need to keep track of.  */
 typedef struct bb_bitmap_sets
@@ -406,13 +486,12 @@
   /* 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;
@@ -426,79 +505,50 @@
 #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
-
-
-/* Basic block list in postorder.  */
-static int *postorder;
+#define BB_LIVE_VOP_ON_EXIT(BB) ((bb_value_sets_t) ((BB)->aux))->vop_on_exit
+
 
 /* This structure is used to keep track of statistics on what
    optimization PRE was able to perform.  */
 static struct
 {
-  /* The number of RHS computations eliminated by PRE.  */
-  int eliminations;
-
   /* The number of new expressions/temporaries generated by PRE.  */
   int insertions;
 
   /* The number of inserts found due to partial anticipation  */
   int pa_insert;
 
+  /* The number of inserts made for code hoisting.  */
+  int hoist_insert;
+
   /* The number of new PHI nodes added by PRE.  */
   int phis;
-
-  /* The number of values found constant.  */
-  int constified;
-
 } pre_stats;
 
 static bool do_partial_partial;
-static pre_expr bitmap_find_leader (bitmap_set_t, unsigned int, gimple);
+static pre_expr bitmap_find_leader (bitmap_set_t, unsigned int);
 static void bitmap_value_insert_into_set (bitmap_set_t, pre_expr);
 static void bitmap_value_replace_in_set (bitmap_set_t, pre_expr);
 static void bitmap_set_copy (bitmap_set_t, bitmap_set_t);
 static bool bitmap_set_contains_value (bitmap_set_t, unsigned int);
 static void bitmap_insert_into_set (bitmap_set_t, pre_expr);
-static void bitmap_insert_into_set_1 (bitmap_set_t, pre_expr,
-				      unsigned int, bool);
 static bitmap_set_t bitmap_set_new (void);
 static tree create_expression_by_pieces (basic_block, pre_expr, gimple_seq *,
-					 gimple, tree);
-static tree find_or_generate_expression (basic_block, pre_expr, gimple_seq *,
-					 gimple);
+					 tree);
+static tree find_or_generate_expression (basic_block, tree, gimple_seq *);
 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 object_allocator<bitmap_set> bitmap_set_pool ("Bitmap sets");
 static bitmap_obstack grand_bitmap_obstack;
 
-/* To avoid adding 300 temporary variables when we only need one, we
-   only create one temporary variable, on demand, and build ssa names
-   off that.  We do have to change the variable if the types don't
-   match the current variable's type.  */
-static tree pretemp;
-static tree storetemp;
-static tree prephitemp;
-
-/* 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.  */
-
-static htab_t phi_translate_table;
-
 /* A three tuple {e, pred, v} used to cache phi translations in the
    phi_translate_table.  */
 
-typedef struct expr_pred_trans_d
+typedef struct expr_pred_trans_d : free_ptr_hash<expr_pred_trans_d>
 {
   /* The expression.  */
   pre_expr e;
@@ -512,26 +562,23 @@
   /* The hashcode for the expression, pred pair. This is cached for
      speed reasons.  */
   hashval_t hashcode;
+
+  /* hash_table support.  */
+  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;
 
-/* Return the hash value for a phi translation table entry.  */
-
-static hashval_t
-expr_pred_trans_hash (const void *p)
+inline hashval_t
+expr_pred_trans_d::hash (const expr_pred_trans_d *e)
 {
-  const_expr_pred_trans_t const ve = (const_expr_pred_trans_t) p;
-  return ve->hashcode;
+  return e->hashcode;
 }
 
-/* Return true if two phi translation table entries are the same.
-   P1 and P2 should point to the expr_pred_trans_t's to be compared.*/
-
-static int
-expr_pred_trans_eq (const void *p1, const void *p2)
+inline int
+expr_pred_trans_d::equal (const expr_pred_trans_d *ve1,
+			  const expr_pred_trans_d *ve2)
 {
-  const_expr_pred_trans_t const ve1 = (const_expr_pred_trans_t) p1;
-  const_expr_pred_trans_t const ve2 = (const_expr_pred_trans_t) p2;
   basic_block b1 = ve1->pred;
   basic_block b2 = ve2->pred;
 
@@ -539,76 +586,63 @@
      be equal.  */
   if (b1 != b2)
     return false;
-  return pre_expr_eq (ve1->e, ve2->e);
+  return pre_expr_d::equal (ve1->e, ve2->e);
 }
 
-/* Search in the phi translation table for the translation of
-   expression E in basic block PRED.
-   Return the translated value, if found, NULL otherwise.  */
-
-static inline pre_expr
-phi_trans_lookup (pre_expr e, basic_block pred)
-{
-  void **slot;
-  struct expr_pred_trans_d ept;
-
-  ept.e = e;
-  ept.pred = pred;
-  ept.hashcode = iterative_hash_hashval_t (pre_expr_hash (e), pred->index);
-  slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode,
-				   NO_INSERT);
-  if (!slot)
-    return NULL;
-  else
-    return ((expr_pred_trans_t) *slot)->v;
-}
-
+/* The phi_translate_table caches phi translations for a given
+   expression and predecessor.  */
+static hash_table<expr_pred_trans_d> *phi_translate_table;
 
 /* Add the tuple mapping from {expression E, basic block PRED} to
-   value V, to the phi translation table.  */
-
-static inline void
-phi_trans_add (pre_expr e, pre_expr v, basic_block pred)
+   the phi translation table and return whether it pre-existed.  */
+
+static inline bool
+phi_trans_add (expr_pred_trans_t *entry, pre_expr e, basic_block pred)
 {
-  void **slot;
-  expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d);
-  new_pair->e = e;
-  new_pair->pred = pred;
-  new_pair->v = v;
-  new_pair->hashcode = iterative_hash_hashval_t (pre_expr_hash (e),
-						 pred->index);
-
-  slot = htab_find_slot_with_hash (phi_translate_table, new_pair,
-				   new_pair->hashcode, INSERT);
+  expr_pred_trans_t *slot;
+  expr_pred_trans_d tem;
+  hashval_t hash = iterative_hash_hashval_t (pre_expr_d::hash (e),
+					     pred->index);
+  tem.e = e;
+  tem.pred = pred;
+  tem.hashcode = hash;
+  slot = phi_translate_table->find_slot_with_hash (&tem, hash, INSERT);
   if (*slot)
-    free (*slot);
-  *slot = (void *) new_pair;
+    {
+      *entry = *slot;
+      return true;
+    }
+
+  *entry = *slot = XNEW (struct expr_pred_trans_d);
+  (*entry)->e = e;
+  (*entry)->pred = pred;
+  (*entry)->hashcode = hash;
+  return false;
 }
 
 
 /* Add expression E to the expression set of value id V.  */
 
-void
+static void
 add_to_value (unsigned int v, pre_expr e)
 {
-  bitmap_set_t set;
-
-  gcc_assert (get_expr_value_id (e) == v);
-
-  if (v >= VEC_length (bitmap_set_t, value_expressions))
+  bitmap set;
+
+  gcc_checking_assert (get_expr_value_id (e) == v);
+
+  if (v >= value_expressions.length ())
     {
-      VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
-			     v + 1);
+      value_expressions.safe_grow_cleared (v + 1);
     }
 
-  set = VEC_index (bitmap_set_t, value_expressions, v);
+  set = value_expressions[v];
   if (!set)
     {
-      set = bitmap_set_new ();
-      VEC_replace (bitmap_set_t, value_expressions, v, set);
+      set = BITMAP_ALLOC (&grand_bitmap_obstack);
+      value_expressions[v] = set;
     }
 
-  bitmap_insert_into_set_1 (set, e, v, true);
+  bitmap_set_bit (set, get_or_alloc_expression_id (e));
 }
 
 /* Create a new bitmap set and return it.  */
@@ -616,7 +650,7 @@
 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;
@@ -627,54 +661,57 @@
 static unsigned int
 get_expr_value_id (pre_expr expr)
 {
+  unsigned int id;
   switch (expr->kind)
     {
     case CONSTANT:
-      {
-	unsigned int id;
-	id = get_constant_value_id (PRE_EXPR_CONSTANT (expr));
-	if (id == 0)
-	  {
-	    id = get_or_alloc_constant_value_id (PRE_EXPR_CONSTANT (expr));
-	    add_to_value (id, expr);
-	  }
-	return id;
-      }
+      id = get_constant_value_id (PRE_EXPR_CONSTANT (expr));
+      break;
     case NAME:
-      return VN_INFO (PRE_EXPR_NAME (expr))->value_id;
+      id = VN_INFO (PRE_EXPR_NAME (expr))->value_id;
+      break;
     case NARY:
-      return PRE_EXPR_NARY (expr)->value_id;
+      id = PRE_EXPR_NARY (expr)->value_id;
+      break;
     case REFERENCE:
-      return PRE_EXPR_REFERENCE (expr)->value_id;
+      id = PRE_EXPR_REFERENCE (expr)->value_id;
+      break;
     default:
       gcc_unreachable ();
     }
+  /* ???  We cannot assert that expr has a value-id (it can be 0), because
+     we assign value-ids only to expressions that have a result
+     in set_hashtable_value_ids.  */
+  return id;
+}
+
+/* Return a SCCVN valnum (SSA name or constant) for the PRE value-id VAL.  */
+
+static tree
+sccvn_valnum_from_value_id (unsigned int val)
+{
+  bitmap_iterator bi;
+  unsigned int i;
+  bitmap exprset = value_expressions[val];
+  EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
+    {
+      pre_expr vexpr = expression_for_id (i);
+      if (vexpr->kind == NAME)
+	return VN_INFO (PRE_EXPR_NAME (vexpr))->valnum;
+      else if (vexpr->kind == CONSTANT)
+	return PRE_EXPR_CONSTANT (vexpr);
+    }
+  return NULL_TREE;
 }
 
 /* Remove an expression EXPR from a bitmapped set.  */
 
 static void
-bitmap_remove_from_set (bitmap_set_t set, pre_expr expr)
+bitmap_remove_expr_from_set (bitmap_set_t set, pre_expr expr)
 {
   unsigned int val  = get_expr_value_id (expr);
-  if (!value_id_constant_p (val))
-    {
-      bitmap_clear_bit (&set->values, val);
-      bitmap_clear_bit (&set->expressions, get_expression_id (expr));
-    }
-}
-
-static void
-bitmap_insert_into_set_1 (bitmap_set_t set, pre_expr expr,
-			  unsigned int val, bool allow_constants)
-{
-  if (allow_constants || !value_id_constant_p (val))
-    {
-      /* We specifically expect this and only this function to be able to
-	 insert constants into a set.  */
-      bitmap_set_bit (&set->values, val);
-      bitmap_set_bit (&set->expressions, get_or_alloc_expression_id (expr));
-    }
+  bitmap_clear_bit (&set->values, val);
+  bitmap_clear_bit (&set->expressions, get_expression_id (expr));
 }
 
 /* Insert an expression EXPR into a bitmapped set.  */
@@ -682,7 +719,15 @@
 static void
 bitmap_insert_into_set (bitmap_set_t set, pre_expr expr)
 {
-  bitmap_insert_into_set_1 (set, expr, get_expr_value_id (expr), false);
+  unsigned int val = get_expr_value_id (expr);
+  if (! value_id_constant_p (val))
+    {
+      /* Note this is the only function causing multiple expressions
+         for the same value to appear in a set.  This is needed for
+	 TMP_GEN, PHI_GEN and NEW_SETs.  */
+      bitmap_set_bit (&set->values, val);
+      bitmap_set_bit (&set->expressions, get_or_alloc_expression_id (expr));
+    }
 }
 
 /* Copy a bitmapped set ORIG, into bitmapped set DEST.  */
@@ -706,15 +751,15 @@
 
 /* Generate an topological-ordered array of bitmap set SET.  */
 
-static VEC(pre_expr, heap) *
+static vec<pre_expr> 
 sorted_array_from_bitmap_set (bitmap_set_t set)
 {
   unsigned int i, j;
   bitmap_iterator bi, bj;
-  VEC(pre_expr, heap) *result;
-
-  /* Pre-allocate roughly enough space for the array.  */
-  result = VEC_alloc (pre_expr, heap, bitmap_count_bits (&set->values));
+  vec<pre_expr> result;
+
+  /* Pre-allocate enough space for the array.  */
+  result.create (bitmap_count_bits (&set->expressions));
 
   FOR_EACH_VALUE_ID_IN_SET (set, i, bi)
     {
@@ -728,47 +773,21 @@
 
 	 If this is somehow a significant lose for some cases, we can
 	 choose which set to walk based on the set size.  */
-      bitmap_set_t exprset = VEC_index (bitmap_set_t, value_expressions, i);
-      FOR_EACH_EXPR_ID_IN_SET (exprset, j, bj)
+      bitmap exprset = value_expressions[i];
+      EXECUTE_IF_SET_IN_BITMAP (exprset, 0, j, bj)
 	{
 	  if (bitmap_bit_p (&set->expressions, j))
-	    VEC_safe_push (pre_expr, heap, result, expression_for_id (j));
+	    result.quick_push (expression_for_id (j));
         }
     }
 
   return result;
 }
 
-/* Perform bitmapped set operation DEST &= ORIG.  */
-
-static void
-bitmap_set_and (bitmap_set_t dest, bitmap_set_t orig)
-{
-  bitmap_iterator bi;
-  unsigned int i;
-
-  if (dest != orig)
-    {
-      bitmap_head temp;
-      bitmap_initialize (&temp, &grand_bitmap_obstack);
-
-      bitmap_and_into (&dest->values, &orig->values);
-      bitmap_copy (&temp, &dest->expressions);
-      EXECUTE_IF_SET_IN_BITMAP (&temp, 0, i, bi)
-	{
-	  pre_expr expr = expression_for_id (i);
-	  unsigned int value_id = get_expr_value_id (expr);
-	  if (!bitmap_bit_p (&dest->values, value_id))
-	    bitmap_clear_bit (&dest->expressions, i);
-	}
-      bitmap_clear (&temp);
-    }
-}
-
-/* Subtract all values and expressions contained in ORIG from DEST.  */
+/* Subtract all expressions contained in ORIG from DEST.  */
 
 static bitmap_set_t
-bitmap_set_subtract (bitmap_set_t dest, bitmap_set_t orig)
+bitmap_set_subtract_expressions (bitmap_set_t dest, bitmap_set_t orig)
 {
   bitmap_set_t result = bitmap_set_new ();
   bitmap_iterator bi;
@@ -787,25 +806,27 @@
   return result;
 }
 
-/* Subtract all the values in bitmap set B from bitmap set A.  */
+/* Subtract all values in bitmap set B from bitmap set A.  */
 
 static void
 bitmap_set_subtract_values (bitmap_set_t a, bitmap_set_t b)
 {
   unsigned int i;
   bitmap_iterator bi;
-  bitmap_head temp;
-
-  bitmap_initialize (&temp, &grand_bitmap_obstack);
-
-  bitmap_copy (&temp, &a->expressions);
-  EXECUTE_IF_SET_IN_BITMAP (&temp, 0, i, bi)
+  pre_expr to_remove = NULL;
+  FOR_EACH_EXPR_ID_IN_SET (a, i, bi)
     {
+      if (to_remove)
+	{
+	  bitmap_remove_expr_from_set (a, to_remove);
+	  to_remove = NULL;
+	}
       pre_expr expr = expression_for_id (i);
-      if (bitmap_set_contains_value (b, get_expr_value_id (expr)))
-	bitmap_remove_from_set (a, expr);
+      if (bitmap_bit_p (&b->values, get_expr_value_id (expr)))
+	to_remove = expr;
     }
-  bitmap_clear (&temp);
+  if (to_remove)
+    bitmap_remove_expr_from_set (a, to_remove);
 }
 
 
@@ -817,9 +838,6 @@
   if (value_id_constant_p (value_id))
     return true;
 
-  if (!set || bitmap_empty_p (&set->expressions))
-    return false;
-
   return bitmap_bit_p (&set->values, value_id);
 }
 
@@ -829,42 +847,6 @@
   return bitmap_bit_p (&set->expressions, get_expression_id (expr));
 }
 
-/* Replace an instance of value LOOKFOR with expression EXPR in SET.  */
-
-static void
-bitmap_set_replace_value (bitmap_set_t set, unsigned int lookfor,
-			  const pre_expr expr)
-{
-  bitmap_set_t exprset;
-  unsigned int i;
-  bitmap_iterator bi;
-
-  if (value_id_constant_p (lookfor))
-    return;
-
-  if (!bitmap_set_contains_value (set, lookfor))
-    return;
-
-  /* The number of expressions having a given value is usually
-     significantly less than the total number of expressions in SET.
-     Thus, rather than check, for each expression in SET, whether it
-     has the value LOOKFOR, we walk the reverse mapping that tells us
-     what expressions have a given value, and see if any of those
-     expressions are in our set.  For large testcases, this is about
-     5-10x faster than walking the bitmap.  If this is somehow a
-     significant lose for some cases, we can choose which set to walk
-     based on the set size.  */
-  exprset = VEC_index (bitmap_set_t, value_expressions, lookfor);
-  FOR_EACH_EXPR_ID_IN_SET (exprset, i, bi)
-    {
-      if (bitmap_clear_bit (&set->expressions, i))
-	{
-	  bitmap_set_bit (&set->expressions, get_expression_id (expr));
-	  return;
-	}
-    }
-}
-
 /* Return true if two bitmap sets are equal.  */
 
 static bool
@@ -880,9 +862,33 @@
 bitmap_value_replace_in_set (bitmap_set_t set, pre_expr expr)
 {
   unsigned int val = get_expr_value_id (expr);
+  if (value_id_constant_p (val))
+    return;
 
   if (bitmap_set_contains_value (set, val))
-    bitmap_set_replace_value (set, val, expr);
+    {
+      /* The number of expressions having a given value is usually
+	 significantly less than the total number of expressions in SET.
+	 Thus, rather than check, for each expression in SET, whether it
+	 has the value LOOKFOR, we walk the reverse mapping that tells us
+	 what expressions have a given value, and see if any of those
+	 expressions are in our set.  For large testcases, this is about
+	 5-10x faster than walking the bitmap.  If this is somehow a
+	 significant lose for some cases, we can choose which set to walk
+	 based on the set size.  */
+      unsigned int i;
+      bitmap_iterator bi;
+      bitmap exprset = value_expressions[val];
+      EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
+	{
+	  if (bitmap_clear_bit (&set->expressions, i))
+	    {
+	      bitmap_set_bit (&set->expressions, get_expression_id (expr));
+	      return;
+	    }
+	}
+      gcc_unreachable ();
+    }
   else
     bitmap_insert_into_set (set, expr);
 }
@@ -911,22 +917,27 @@
 static void
 print_pre_expr (FILE *outfile, const pre_expr expr)
 {
+  if (! expr)
+    {
+      fprintf (outfile, "NULL");
+      return;
+    }
   switch (expr->kind)
     {
     case CONSTANT:
-      print_generic_expr (outfile, PRE_EXPR_CONSTANT (expr), 0);
+      print_generic_expr (outfile, PRE_EXPR_CONSTANT (expr));
       break;
     case NAME:
-      print_generic_expr (outfile, PRE_EXPR_NAME (expr), 0);
+      print_generic_expr (outfile, PRE_EXPR_NAME (expr));
       break;
     case NARY:
       {
 	unsigned int i;
 	vn_nary_op_t nary = PRE_EXPR_NARY (expr);
-	fprintf (outfile, "{%s,", tree_code_name [nary->opcode]);
+	fprintf (outfile, "{%s,", get_tree_code_name (nary->opcode));
 	for (i = 0; i < nary->length; i++)
 	  {
-	    print_generic_expr (outfile, nary->op[i], 0);
+	    print_generic_expr (outfile, nary->op[i]);
 	    if (i != (unsigned) nary->length - 1)
 	      fprintf (outfile, ",");
 	  }
@@ -941,14 +952,14 @@
 	vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
 	fprintf (outfile, "{");
 	for (i = 0;
-	     VEC_iterate (vn_reference_op_s, ref->operands, i, vro);
+	     ref->operands.iterate (i, &vro);
 	     i++)
 	  {
 	    bool closebrace = false;
 	    if (vro->opcode != SSA_NAME
 		&& TREE_CODE_CLASS (vro->opcode) != tcc_declaration)
 	      {
-		fprintf (outfile, "%s", tree_code_name [vro->opcode]);
+		fprintf (outfile, "%s", get_tree_code_name (vro->opcode));
 		if (vro->op0)
 		  {
 		    fprintf (outfile, "<");
@@ -957,28 +968,28 @@
 	      }
 	    if (vro->op0)
 	      {
-		print_generic_expr (outfile, vro->op0, 0);
+		print_generic_expr (outfile, vro->op0);
 		if (vro->op1)
 		  {
 		    fprintf (outfile, ",");
-		    print_generic_expr (outfile, vro->op1, 0);
+		    print_generic_expr (outfile, vro->op1);
 		  }
 		if (vro->op2)
 		  {
 		    fprintf (outfile, ",");
-		    print_generic_expr (outfile, vro->op2, 0);
+		    print_generic_expr (outfile, vro->op2);
 		  }
 	      }
 	    if (closebrace)
 		fprintf (outfile, ">");
-	    if (i != VEC_length (vn_reference_op_s, ref->operands) - 1)
+	    if (i != ref->operands.length () - 1)
 	      fprintf (outfile, ",");
 	  }
 	fprintf (outfile, "}");
 	if (ref->vuse)
 	  {
 	    fprintf (outfile, "@");
-	    print_generic_expr (outfile, ref->vuse, 0);
+	    print_generic_expr (outfile, ref->vuse);
 	  }
       }
       break;
@@ -1030,17 +1041,34 @@
   print_bitmap_set (stderr, set, "debug", 0);
 }
 
+void debug_bitmap_sets_for (basic_block);
+
+DEBUG_FUNCTION void
+debug_bitmap_sets_for (basic_block bb)
+{
+  print_bitmap_set (stderr, AVAIL_OUT (bb), "avail_out", bb->index);
+  print_bitmap_set (stderr, EXP_GEN (bb), "exp_gen", bb->index);
+  print_bitmap_set (stderr, PHI_GEN (bb), "phi_gen", bb->index);
+  print_bitmap_set (stderr, TMP_GEN (bb), "tmp_gen", bb->index);
+  print_bitmap_set (stderr, ANTIC_IN (bb), "antic_in", bb->index);
+  if (do_partial_partial)
+    print_bitmap_set (stderr, PA_IN (bb), "pa_in", bb->index);
+  print_bitmap_set (stderr, NEW_SETS (bb), "new_sets", bb->index);
+}
+
 /* Print out the expressions that have VAL to OUTFILE.  */
 
-void
+static void
 print_value_expressions (FILE *outfile, unsigned int val)
 {
-  bitmap_set_t set = VEC_index (bitmap_set_t, value_expressions, val);
+  bitmap set = value_expressions[val];
   if (set)
     {
+      bitmap_set x;
       char s[10];
       sprintf (s, "%04d", val);
-      print_bitmap_set (outfile, set, s, 0);
+      x.expressions = *set;
+      print_bitmap_set (outfile, &x, s, 0);
     }
 }
 
@@ -1068,7 +1096,7 @@
   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);
@@ -1077,29 +1105,6 @@
   return newexpr;
 }
 
-/* Given a value id V, find the actual tree representing the constant
-   value if there is one, and return it. Return NULL if we can't find
-   a constant.  */
-
-static tree
-get_constant_for_value_id (unsigned int v)
-{
-  if (value_id_constant_p (v))
-    {
-      unsigned int i;
-      bitmap_iterator bi;
-      bitmap_set_t exprset = VEC_index (bitmap_set_t, value_expressions, v);
-
-      FOR_EACH_EXPR_ID_IN_SET (exprset, i, bi)
-	{
-	  pre_expr expr = expression_for_id (i);
-	  if (expr->kind == CONSTANT)
-	    return PRE_EXPR_CONSTANT (expr);
-	}
-    }
-  return NULL;
-}
-
 /* Get or allocate a pre_expr for a piece of GIMPLE, and return it.
    Currently only supports constants and SSA_NAMES.  */
 static pre_expr
@@ -1109,35 +1114,11 @@
     return get_or_alloc_expr_for_name (t);
   else if (is_gimple_min_invariant (t))
     return get_or_alloc_expr_for_constant (t);
-  else
-    {
-      /* More complex expressions can result from SCCVN expression
-	 simplification that inserts values for them.  As they all
-	 do not have VOPs the get handled by the nary ops struct.  */
-      vn_nary_op_t result;
-      unsigned int result_id;
-      vn_nary_op_lookup (t, &result);
-      if (result != NULL)
-	{
-	  pre_expr e = (pre_expr) pool_alloc (pre_expr_pool);
-	  e->kind = NARY;
-	  PRE_EXPR_NARY (e) = result;
-	  result_id = lookup_expression_id (e);
-	  if (result_id != 0)
-	    {
-	      pool_free (pre_expr_pool, e);
-	      e = expression_for_id (result_id);
-	      return e;
-	    }
-	  alloc_expression_id (e);
-	  return e;
-	}
-    }
-  return NULL;
+  gcc_unreachable ();
 }
 
 /* Return the folded version of T if T, when folded, is a gimple
-   min_invariant.  Otherwise, return T.  */
+   min_invariant or an SSA name.  Otherwise, return T.  */
 
 static pre_expr
 fully_constant_expression (pre_expr e)
@@ -1149,85 +1130,14 @@
     case NARY:
       {
 	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:
-	    {
-	      /* We have to go from trees to pre exprs to value ids to
-		 constants.  */
-	      tree naryop0 = nary->op[0];
-	      tree naryop1 = nary->op[1];
-	      tree result;
-	      if (!is_gimple_min_invariant (naryop0))
-		{
-		  pre_expr rep0 = get_or_alloc_expr_for (naryop0);
-		  unsigned int vrep0 = get_expr_value_id (rep0);
-		  tree const0 = get_constant_for_value_id (vrep0);
-		  if (const0)
-		    naryop0 = fold_convert (TREE_TYPE (naryop0), const0);
-		}
-	      if (!is_gimple_min_invariant (naryop1))
-		{
-		  pre_expr rep1 = get_or_alloc_expr_for (naryop1);
-		  unsigned int vrep1 = get_expr_value_id (rep1);
-		  tree const1 = get_constant_for_value_id (vrep1);
-		  if (const1)
-		    naryop1 = fold_convert (TREE_TYPE (naryop1), const1);
-		}
-	      result = fold_binary (nary->opcode, nary->type,
-				    naryop0, naryop1);
-	      if (result && is_gimple_min_invariant (result))
-		return get_or_alloc_expr_for_constant (result);
-	      /* We might have simplified the expression to a
-		 SSA_NAME for example from x_1 * 1.  But we cannot
-		 insert a PHI for x_1 unconditionally as x_1 might
-		 not be available readily.  */
-	      return e;
-	    }
-	  case tcc_reference:
-	    if (nary->opcode != REALPART_EXPR
-		&& nary->opcode != IMAGPART_EXPR
-		&& nary->opcode != VIEW_CONVERT_EXPR)
-	      return e;
-	    /* Fallthrough.  */
-	  case tcc_unary:
-do_unary:
-	    {
-	      /* We have to go from trees to pre exprs to value ids to
-		 constants.  */
-	      tree naryop0 = nary->op[0];
-	      tree const0, result;
-	      if (is_gimple_min_invariant (naryop0))
-		const0 = naryop0;
-	      else
-		{
-		  pre_expr rep0 = get_or_alloc_expr_for (naryop0);
-		  unsigned int vrep0 = get_expr_value_id (rep0);
-		  const0 = get_constant_for_value_id (vrep0);
-		}
-	      result = NULL;
-	      if (const0)
-		{
-		  tree type1 = TREE_TYPE (nary->op[0]);
-		  const0 = fold_convert (type1, const0);
-		  result = fold_unary (nary->opcode, nary->type, const0);
-		}
-	      if (result && is_gimple_min_invariant (result))
-		return get_or_alloc_expr_for_constant (result);
-	      return e;
-	    }
-	  default:
-	    return e;
-	  }
+	tree res = vn_nary_simplify (nary);
+	if (!res)
+	  return e;
+	if (is_gimple_min_invariant (res))
+	  return get_or_alloc_expr_for_constant (res);
+	if (TREE_CODE (res) == SSA_NAME)
+	  return get_or_alloc_expr_for_name (res);
+	return e;
       }
     case REFERENCE:
       {
@@ -1248,12 +1158,12 @@
    in case the new vuse doesn't change the value id of the OPERANDS.  */
 
 static tree
-translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
+translate_vuse_through_block (vec<vn_reference_op_s> operands,
 			      alias_set_type set, tree type, tree vuse,
 			      basic_block phiblock,
 			      basic_block block, bool *same_valid)
 {
-  gimple phi = SSA_NAME_DEF_STMT (vuse);
+  gimple *phi = SSA_NAME_DEF_STMT (vuse);
   ao_ref ref;
   edge e = NULL;
   bool use_oracle;
@@ -1291,9 +1201,11 @@
       if (use_oracle)
 	{
 	  bitmap visited = NULL;
+	  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, &visited);
+	  vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false,
+					   NULL, NULL);
 	  if (visited)
 	    BITMAP_FREE (visited);
 	}
@@ -1318,17 +1230,20 @@
 }
 
 /* Like bitmap_find_leader, but checks for the value existing in SET1 *or*
-   SET2.  This is used to avoid making a set consisting of the union
-   of PA_IN and ANTIC_IN during insert.  */
+   SET2 *or* SET3.  This is used to avoid making a set consisting of the union
+   of PA_IN and ANTIC_IN during insert and phi-translation.  */
 
 static inline pre_expr
-find_leader_in_sets (unsigned int val, bitmap_set_t set1, bitmap_set_t set2)
+find_leader_in_sets (unsigned int val, bitmap_set_t set1, bitmap_set_t set2,
+		     bitmap_set_t set3 = NULL)
 {
   pre_expr result;
 
-  result = bitmap_find_leader (set1, val, NULL);
+  result = bitmap_find_leader (set1, val);
   if (!result && set2)
-    result = bitmap_find_leader (set2, val, NULL);
+    result = bitmap_find_leader (set2, val);
+  if (!result && set3)
+    result = bitmap_find_leader (set3, val);
   return result;
 }
 
@@ -1348,7 +1263,7 @@
     case NARY:
       return PRE_EXPR_NARY (e)->type;
     }
-  gcc_unreachable();
+  gcc_unreachable ();
 }
 
 /* Get a representative SSA_NAME for a given expression.
@@ -1362,14 +1277,13 @@
 static tree
 get_representative_for (const pre_expr e)
 {
-  tree exprtype;
   tree name;
   unsigned int value_id = get_expr_value_id (e);
 
   switch (e->kind)
     {
     case NAME:
-      return PRE_EXPR_NAME (e);
+      return VN_INFO (PRE_EXPR_NAME (e))->valnum;
     case CONSTANT:
       return PRE_EXPR_CONSTANT (e);
     case NARY:
@@ -1379,54 +1293,38 @@
 	   and pick out an SSA_NAME.  */
 	unsigned int i;
 	bitmap_iterator bi;
-	bitmap_set_t exprs = VEC_index (bitmap_set_t, value_expressions,
-					value_id);
-	FOR_EACH_EXPR_ID_IN_SET (exprs, i, bi)
+	bitmap exprs = value_expressions[value_id];
+	EXECUTE_IF_SET_IN_BITMAP (exprs, 0, i, bi)
 	  {
 	    pre_expr rep = expression_for_id (i);
 	    if (rep->kind == NAME)
-	      return PRE_EXPR_NAME (rep);
+	      return VN_INFO (PRE_EXPR_NAME (rep))->valnum;
+	    else if (rep->kind == CONSTANT)
+	      return PRE_EXPR_CONSTANT (rep);
 	  }
       }
       break;
     }
+
   /* If we reached here we couldn't find an SSA_NAME.  This can
      happen when we've discovered a value that has never appeared in
-     the program as set to an SSA_NAME, most likely as the result of
-     phi translation.  */
-  if (dump_file)
-    {
-      fprintf (dump_file,
-	       "Could not find SSA_NAME representative for expression:");
-      print_pre_expr (dump_file, e);
-      fprintf (dump_file, "\n");
-    }
-
-  exprtype = get_expr_type (e);
-
-  /* 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);
-    }
-
-  name = make_ssa_name (pretemp, gimple_build_nop ());
+     the program as set to an SSA_NAME, as the result of phi translation.
+     Create one here.
+     ???  We should be able to re-use this when we insert the statement
+     to compute it.  */
+  name = make_temp_ssa_name (get_expr_type (e), gimple_build_nop (), "pretmp");
   VN_INFO_GET (name)->value_id = value_id;
-  if (e->kind == CONSTANT)
-    VN_INFO (name)->valnum = PRE_EXPR_CONSTANT (e);
-  else
-    VN_INFO (name)->valnum = name;
-
+  VN_INFO (name)->valnum = name;
+  /* ???  For now mark this SSA name for release by SCCVN.  */
+  VN_INFO (name)->needs_insertion = true;
   add_to_value (value_id, get_or_alloc_expr_for_name (name));
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Created SSA_NAME representative ");
-      print_generic_expr (dump_file, name, 0);
+      print_generic_expr (dump_file, name);
       fprintf (dump_file, " for expression:");
       print_pre_expr (dump_file, e);
-      fprintf (dump_file, "\n");
+      fprintf (dump_file, " (%04d)\n", value_id);
     }
 
   return name;
@@ -1453,33 +1351,26 @@
 	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)));
-
-	for (i = 0; i < newnary.length; i++)
+	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++)
 	  {
-	    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)
-		  {
-		    tree name = get_representative_for (result);
-		    if (!name)
-		      return NULL;
-		    newnary.op[i] = name;
-		  }
+		  newnary->op[i] = get_representative_for (result);
 		else if (!result)
 		  return NULL;
 
-		changed |= newnary.op[i] != nary->op[i];
+		changed |= newnary->op[i] != nary->op[i];
 	      }
 	  }
 	if (changed)
@@ -1487,48 +1378,102 @@
 	    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],
+	    PRE_EXPR_NARY (expr) = newnary;
+	    constant = fully_constant_expression (expr);
+	    PRE_EXPR_NARY (expr) = nary;
+	    if (constant != expr)
+	      {
+		/* For non-CONSTANTs we have to make sure we can eventually
+		   insert the expression.  Which means we need to have a
+		   leader for it.  */
+		if (constant->kind != CONSTANT)
+		  {
+		    /* Do not allow simplifications to non-constants over
+		       backedges as this will likely result in a loop PHI node
+		       to be inserted and increased register pressure.
+		       See PR77498 - this avoids doing predcoms work in
+		       a less efficient way.  */
+		    if (find_edge (pred, phiblock)->flags & EDGE_DFS_BACK)
+		      ;
+		    else
+		      {
+			unsigned value_id = get_expr_value_id (constant);
+			constant = find_leader_in_sets (value_id, set1, set2,
+							AVAIL_OUT (pred));
+			if (constant)
+			  return constant;
+		      }
+		  }
+		else
+		  return constant;
+	      }
+
+	    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);
 
-	    expr = (pre_expr) pool_alloc (pre_expr_pool);
+	    expr = pre_expr_pool.allocate ();
 	    expr->kind = NARY;
 	    expr->id = 0;
 	    if (nary)
 	      {
 		PRE_EXPR_NARY (expr) = nary;
-		constant = fully_constant_expression (expr);
-		if (constant != expr)
-		  return constant;
-
 		new_val_id = nary->value_id;
 		get_or_alloc_expression_id (expr);
+		/* When we end up re-using a value number make sure that
+		   doesn't have unrelated (which we can't check here)
+		   range or points-to info on it.  */
+		if (result
+		    && INTEGRAL_TYPE_P (TREE_TYPE (result))
+		    && SSA_NAME_RANGE_INFO (result)
+		    && ! SSA_NAME_IS_DEFAULT_DEF (result))
+		  {
+		    if (! VN_INFO (result)->info.range_info)
+		      {
+			VN_INFO (result)->info.range_info
+			  = SSA_NAME_RANGE_INFO (result);
+			VN_INFO (result)->range_info_anti_range_p
+			  = SSA_NAME_ANTI_RANGE_P (result);
+		      }
+		    if (dump_file && (dump_flags & TDF_DETAILS))
+		      {
+			fprintf (dump_file, "clearing range info of ");
+			print_generic_expr (dump_file, result);
+			fprintf (dump_file, "\n");
+		      }
+		    SSA_NAME_RANGE_INFO (result) = NULL;
+		  }
+		else if (result
+			 && POINTER_TYPE_P (TREE_TYPE (result))
+			 && SSA_NAME_PTR_INFO (result)
+			 && ! SSA_NAME_IS_DEFAULT_DEF (result))
+		  {
+		    if (! VN_INFO (result)->info.ptr_info)
+		      VN_INFO (result)->info.ptr_info
+			= SSA_NAME_PTR_INFO (result);
+		    if (dump_file && (dump_flags & TDF_DETAILS))
+		      {
+			fprintf (dump_file, "clearing points-to info of ");
+			print_generic_expr (dump_file, result);
+			fprintf (dump_file, "\n");
+		      }
+		    SSA_NAME_PTR_INFO (result) = NULL;
+		  }
 	      }
 	    else
 	      {
 		new_val_id = get_next_value_id ();
-		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],
+		value_expressions.safe_grow_cleared (get_max_value_id () + 1);
+		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);
-		if (constant != expr)
-		  return constant;
 		get_or_alloc_expression_id (expr);
 	      }
 	    add_to_value (new_val_id, expr);
@@ -1540,134 +1485,80 @@
     case REFERENCE:
       {
 	vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
-	VEC (vn_reference_op_s, heap) *operands = ref->operands;
+	vec<vn_reference_op_s> operands = ref->operands;
 	tree vuse = ref->vuse;
 	tree newvuse = vuse;
-	VEC (vn_reference_op_s, heap) *newoperands = NULL;
+	vec<vn_reference_op_s> newoperands = vNULL;
 	bool changed = false, same_valid = true;
-	unsigned int i, j;
+	unsigned int i, n;
 	vn_reference_op_t operand;
 	vn_reference_t newref;
 
-	for (i = 0, j = 0;
-	     VEC_iterate (vn_reference_op_s, operands, i, operand); i++, j++)
+	for (i = 0; operands.iterate (i, &operand); i++)
 	  {
 	    pre_expr opresult;
 	    pre_expr leader;
-	    tree oldop0 = operand->op0;
-	    tree oldop1 = operand->op1;
-	    tree oldop2 = operand->op2;
-	    tree op0 = oldop0;
-	    tree op1 = oldop1;
-	    tree op2 = oldop2;
+	    tree op[3];
 	    tree type = operand->type;
 	    vn_reference_op_s newop = *operand;
-
-	    if (op0 && TREE_CODE (op0) == SSA_NAME)
+	    op[0] = operand->op0;
+	    op[1] = operand->op1;
+	    op[2] = operand->op2;
+	    for (n = 0; n < 3; ++n)
 	      {
-		unsigned int op_val_id = VN_INFO (op0)->value_id;
-		leader = find_leader_in_sets (op_val_id, set1, set2);
-		opresult = phi_translate (leader, set1, set2, pred, phiblock);
-		if (opresult && opresult != leader)
+		unsigned int op_val_id;
+		if (!op[n])
+		  continue;
+		if (TREE_CODE (op[n]) != SSA_NAME)
 		  {
-		    tree name = get_representative_for (opresult);
-		    if (!name)
+		    /* We can't possibly insert these.  */
+		    if (n != 0
+			&& !is_gimple_min_invariant (op[n]))
 		      break;
-		    op0 = name;
+		    continue;
 		  }
-		else if (!opresult)
-		  break;
-	      }
-	    changed |= op0 != oldop0;
-
-	    if (op1 && TREE_CODE (op1) == SSA_NAME)
-	      {
-		unsigned int op_val_id = VN_INFO (op1)->value_id;
+		op_val_id = VN_INFO (op[n])->value_id;
 		leader = find_leader_in_sets (op_val_id, set1, set2);
 		opresult = phi_translate (leader, set1, set2, pred, phiblock);
 		if (opresult && opresult != leader)
 		  {
 		    tree name = get_representative_for (opresult);
-		    if (!name)
-		      break;
-		    op1 = name;
-		  }
-		else if (!opresult)
-		  break;
-	      }
-	    /* We can't possibly insert these.  */
-	    else if (op1 && !is_gimple_min_invariant (op1))
-	      break;
-	    changed |= op1 != oldop1;
-	    if (op2 && TREE_CODE (op2) == SSA_NAME)
-	      {
-		unsigned int op_val_id = VN_INFO (op2)->value_id;
-		leader = find_leader_in_sets (op_val_id, set1, set2);
-		opresult = phi_translate (leader, set1, set2, pred, phiblock);
-		if (opresult && opresult != leader)
-		  {
-		    tree name = get_representative_for (opresult);
-		    if (!name)
-		      break;
-		    op2 = name;
+		    changed |= name != op[n];
+		    op[n] = name;
 		  }
 		else if (!opresult)
 		  break;
 	      }
-	    /* We can't possibly insert these.  */
-	    else if (op2 && !is_gimple_min_invariant (op2))
-	      break;
-	    changed |= op2 != oldop2;
-
-	    if (!newoperands)
-	      newoperands = VEC_copy (vn_reference_op_s, heap, operands);
-	    /* We may have changed from an SSA_NAME to a constant */
-	    if (newop.opcode == SSA_NAME && TREE_CODE (op0) != SSA_NAME)
-	      newop.opcode = TREE_CODE (op0);
-	    newop.type = type;
-	    newop.op0 = op0;
-	    newop.op1 = op1;
-	    newop.op2 = op2;
-	    /* 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 (op0) == INTEGER_CST
-		&& TREE_CODE (op1) == INTEGER_CST
-		&& TREE_CODE (op2) == INTEGER_CST)
+	    if (n != 3)
 	      {
-		double_int off = tree_to_double_int (op0);
-		off = double_int_add (off,
-				      double_int_neg
-				        (tree_to_double_int (op1)));
-		off = double_int_mul (off, tree_to_double_int (op2));
-		if (double_int_fits_in_shwi_p (off))
-		  newop.off = off.low;
+		newoperands.release ();
+		return NULL;
 	      }
-	    VEC_replace (vn_reference_op_s, newoperands, j, &newop);
-	    /* If it transforms from an SSA_NAME to an address, fold with
-	       a preceding indirect reference.  */
-	    if (j > 0 && op0 && TREE_CODE (op0) == ADDR_EXPR
-		&& VEC_index (vn_reference_op_s,
-			      newoperands, j - 1)->opcode == MEM_REF)
-	      vn_reference_fold_indirect (&newoperands, &j);
+	    if (!changed)
+	      continue;
+	    if (!newoperands.exists ())
+	      newoperands = operands.copy ();
+	    /* We may have changed from an SSA_NAME to a constant */
+	    if (newop.opcode == SSA_NAME && TREE_CODE (op[0]) != SSA_NAME)
+	      newop.opcode = TREE_CODE (op[0]);
+	    newop.type = type;
+	    newop.op0 = op[0];
+	    newop.op1 = op[1];
+	    newop.op2 = op[2];
+	    newoperands[i] = newop;
 	  }
-	if (i != VEC_length (vn_reference_op_s, operands))
-	  {
-	    if (newoperands)
-	      VEC_free (vn_reference_op_s, heap, newoperands);
-	    return NULL;
-	  }
+	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);
 	    if (newvuse == NULL_TREE)
 	      {
-		VEC_free (vn_reference_op_s, heap, newoperands);
+		newoperands.release ();
 		return NULL;
 	      }
 	  }
@@ -1676,86 +1567,50 @@
 	  {
 	    unsigned int new_val_id;
 	    pre_expr constant;
-	    bool converted = false;
 
 	    tree result = vn_reference_lookup_pieces (newvuse, ref->set,
 						      ref->type,
-						      newoperands,
+						      newoperands.exists ()
+						      ? newoperands : operands,
 						      &newref, VN_WALK);
 	    if (result)
-	      VEC_free (vn_reference_op_s, heap, newoperands);
-
+	      newoperands.release ();
+
+	    /* We can always insert constants, so if we have a partial
+	       redundant constant load of another type try to translate it
+	       to a constant of appropriate type.  */
+	    if (result && is_gimple_min_invariant (result))
+	      {
+		tree tem = result;
+		if (!useless_type_conversion_p (ref->type, TREE_TYPE (result)))
+		  {
+		    tem = fold_unary (VIEW_CONVERT_EXPR, ref->type, result);
+		    if (tem && !is_gimple_min_invariant (tem))
+		      tem = NULL_TREE;
+		  }
+		if (tem)
+		  return get_or_alloc_expr_for_constant (tem);
+	      }
+
+	    /* If we'd have to convert things we would need to validate
+	       if we can insert the translated expression.  So fail
+	       here for now - we cannot insert an alias with a different
+	       type in the VN tables either, as that would assert.  */
 	    if (result
 		&& !useless_type_conversion_p (ref->type, TREE_TYPE (result)))
-	      {
-		result = fold_build1 (VIEW_CONVERT_EXPR, ref->type, result);
-		converted = true;
-	      }
+	      return NULL;
 	    else if (!result && newref
 		     && !useless_type_conversion_p (ref->type, newref->type))
 	      {
-		VEC_free (vn_reference_op_s, heap, newoperands);
+		newoperands.release ();
 		return NULL;
 	      }
 
-	    if (result && is_gimple_min_invariant (result))
-	      {
-	        gcc_assert (!newoperands);
-	        return get_or_alloc_expr_for_constant (result);
-	      }
-
-	    expr = (pre_expr) pool_alloc (pre_expr_pool);
+	    expr = pre_expr_pool.allocate ();
 	    expr->kind = REFERENCE;
 	    expr->id = 0;
 
-	    if (converted)
-	      {
-		vn_nary_op_t nary;
-		tree nresult;
-
-		gcc_assert (CONVERT_EXPR_P (result)
-			    || TREE_CODE (result) == VIEW_CONVERT_EXPR);
-
-		nresult = vn_nary_op_lookup_pieces (1, TREE_CODE (result),
-						    TREE_TYPE (result),
-						    TREE_OPERAND (result, 0),
-						    NULL_TREE, NULL_TREE,
-						    NULL_TREE,
-						    &nary);
-		if (nresult && is_gimple_min_invariant (nresult))
-		  return get_or_alloc_expr_for_constant (nresult);
-
-		expr->kind = NARY;
-		if (nary)
-		  {
-		    PRE_EXPR_NARY (expr) = nary;
-		    constant = fully_constant_expression (expr);
-		    if (constant != expr)
-		      return constant;
-
-		    new_val_id = nary->value_id;
-		    get_or_alloc_expression_id (expr);
-		  }
-		else
-		  {
-		    new_val_id = get_next_value_id ();
-		    VEC_safe_grow_cleared (bitmap_set_t, heap,
-					   value_expressions,
-					   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,
-						     new_val_id);
-		    PRE_EXPR_NARY (expr) = nary;
-		    constant = fully_constant_expression (expr);
-		    if (constant != expr)
-		      return constant;
-		    get_or_alloc_expression_id (expr);
-		  }
-	      }
-	    else if (newref)
+	    if (newref)
 	      {
 		PRE_EXPR_REFERENCE (expr) = newref;
 		constant = fully_constant_expression (expr);
@@ -1770,17 +1625,18 @@
 		if (changed || !same_valid)
 		  {
 		    new_val_id = get_next_value_id ();
-		    VEC_safe_grow_cleared (bitmap_set_t, heap,
-					   value_expressions,
-					   get_max_value_id() + 1);
+		    value_expressions.safe_grow_cleared
+		      (get_max_value_id () + 1);
 		  }
 		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 = NULL;
+		newoperands = vNULL;
 		PRE_EXPR_REFERENCE (expr) = newref;
 		constant = fully_constant_expression (expr);
 		if (constant != expr)
@@ -1789,46 +1645,34 @@
 	      }
 	    add_to_value (new_val_id, expr);
 	  }
-	VEC_free (vn_reference_op_s, heap, newoperands);
+	newoperands.release ();
 	return expr;
       }
       break;
 
     case NAME:
       {
-	gimple phi = NULL;
-	edge e;
-	gimple def_stmt;
 	tree name = PRE_EXPR_NAME (expr);
-
-	def_stmt = SSA_NAME_DEF_STMT (name);
+	gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+	/* If the SSA name is defined by a PHI node in this block,
+	   translate it.  */
 	if (gimple_code (def_stmt) == GIMPLE_PHI
 	    && gimple_bb (def_stmt) == phiblock)
-	  phi = def_stmt;
-	else
-	  return expr;
-
-	e = find_edge (pred, gimple_bb (phi));
-	if (e)
 	  {
-	    tree def = PHI_ARG_DEF (phi, e->dest_idx);
-	    pre_expr newexpr;
-
-	    if (TREE_CODE (def) == SSA_NAME)
-	      def = VN_INFO (def)->valnum;
+	    edge e = find_edge (pred, gimple_bb (def_stmt));
+	    tree def = PHI_ARG_DEF (def_stmt, e->dest_idx);
 
 	    /* Handle constant. */
 	    if (is_gimple_min_invariant (def))
 	      return get_or_alloc_expr_for_constant (def);
 
-	    if (TREE_CODE (def) == SSA_NAME && ssa_undefined_value_p (def))
-	      return NULL;
-
-	    newexpr = get_or_alloc_expr_for_name (def);
-	    return newexpr;
+	    return get_or_alloc_expr_for_name (def);
 	  }
+	/* 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;
       }
-      return expr;
 
     default:
       gcc_unreachable ();
@@ -1841,6 +1685,7 @@
 phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
 	       basic_block pred, basic_block phiblock)
 {
+  expr_pred_trans_t slot = NULL;
   pre_expr phitrans;
 
   if (!expr)
@@ -1853,21 +1698,28 @@
   if (value_id_constant_p (get_expr_value_id (expr)))
     return expr;
 
+  /* Don't add translations of NAMEs as those are cheap to translate.  */
   if (expr->kind != NAME)
     {
-      phitrans = phi_trans_lookup (expr, pred);
-      if (phitrans)
-	return phitrans;
+      if (phi_trans_add (&slot, expr, pred))
+	return slot->v;
+      /* Store NULL for the value we want to return in the case of
+	 recursing.  */
+      slot->v = NULL;
     }
 
   /* Translate.  */
   phitrans = phi_translate_1 (expr, set1, set2, pred, phiblock);
 
-  /* Don't add empty translations to the cache.  Neither add
-     translations of NAMEs as those are cheap to translate.  */
-  if (phitrans
-      && expr->kind != NAME)
-    phi_trans_add (expr, phitrans, pred);
+  if (slot)
+    {
+      if (phitrans)
+	slot->v = phitrans;
+      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);
+    }
 
   return phitrans;
 }
@@ -1881,7 +1733,7 @@
 phi_translate_set (bitmap_set_t dest, bitmap_set_t set, basic_block pred,
 		   basic_block phiblock)
 {
-  VEC (pre_expr, heap) *exprs;
+  vec<pre_expr> exprs;
   pre_expr expr;
   int i;
 
@@ -1892,7 +1744,7 @@
     }
 
   exprs = sorted_array_from_bitmap_set (set);
-  FOR_EACH_VEC_ELT (pre_expr, exprs, i, expr)
+  FOR_EACH_VEC_ELT (exprs, i, expr)
     {
       pre_expr translated;
       translated = phi_translate (expr, set, NULL, pred, phiblock);
@@ -1908,24 +1760,23 @@
       else
 	bitmap_value_insert_into_set (dest, translated);
     }
-  VEC_free (pre_expr, heap, exprs);
+  exprs.release ();
 }
 
 /* Find the leader for a value (i.e., the name representing that
-   value) in a given set, and return it.  If STMT is non-NULL it
-   makes sure the defining statement for the leader dominates it.
-   Return NULL if no leader is found.  */
+   value) in a given set, and return it.  Return NULL if no leader
+   is found.  */
 
 static pre_expr
-bitmap_find_leader (bitmap_set_t set, unsigned int val, gimple stmt)
+bitmap_find_leader (bitmap_set_t set, unsigned int val)
 {
   if (value_id_constant_p (val))
     {
       unsigned int i;
       bitmap_iterator bi;
-      bitmap_set_t exprset = VEC_index (bitmap_set_t, value_expressions, val);
-
-      FOR_EACH_EXPR_ID_IN_SET (exprset, i, bi)
+      bitmap exprset = value_expressions[val];
+
+      EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
 	{
 	  pre_expr expr = expression_for_id (i);
 	  if (expr->kind == CONSTANT)
@@ -1947,27 +1798,10 @@
 	 choose which set to walk based on which set is smaller.  */
       unsigned int i;
       bitmap_iterator bi;
-      bitmap_set_t exprset = VEC_index (bitmap_set_t, value_expressions, val);
-
-      EXECUTE_IF_AND_IN_BITMAP (&exprset->expressions,
-				&set->expressions, 0, i, bi)
-	{
-	  pre_expr val = expression_for_id (i);
-	  /* At the point where stmt is not null, there should always
-	     be an SSA_NAME first in the list of expressions.  */
-	  if (stmt)
-	    {
-	      gimple def_stmt = SSA_NAME_DEF_STMT (PRE_EXPR_NAME (val));
-	      if (gimple_code (def_stmt) != GIMPLE_PHI
-		  && gimple_bb (def_stmt) == gimple_bb (stmt)
-		  /* PRE insertions are at the end of the basic-block
-		     and have UID 0.  */
-		  && (gimple_uid (def_stmt) == 0
-		      || gimple_uid (def_stmt) >= gimple_uid (stmt)))
-		continue;
-	    }
-	  return val;
-	}
+      bitmap exprset = value_expressions[val];
+
+      EXECUTE_IF_AND_IN_BITMAP (exprset, &set->expressions, 0, i, bi)
+	return expression_for_id (i);
     }
   return NULL;
 }
@@ -1984,7 +1818,7 @@
 {
   tree vuse = PRE_EXPR_REFERENCE (expr)->vuse;
   vn_reference_t refx = PRE_EXPR_REFERENCE (expr);
-  gimple def;
+  gimple *def;
   gimple_stmt_iterator gsi;
   unsigned id = get_expression_id (expr);
   bool res = false;
@@ -2052,57 +1886,19 @@
 }
 
 
-#define union_contains_value(SET1, SET2, VAL)			\
-  (bitmap_set_contains_value ((SET1), (VAL))			\
-   || ((SET2) && bitmap_set_contains_value ((SET2), (VAL))))
-
-/* Determine if vn_reference_op_t VRO is legal in SET1 U SET2.
- */
+/* Determine if OP is valid in SET1 U SET2, which it is when the union
+   contains its value-id.  */
+
 static bool
-vro_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2,
-		   vn_reference_op_t vro)
+op_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, tree op)
 {
-  if (vro->op0 && TREE_CODE (vro->op0) == SSA_NAME)
+  if (op && TREE_CODE (op) == SSA_NAME)
     {
-      struct pre_expr_d temp;
-      temp.kind = NAME;
-      temp.id = 0;
-      PRE_EXPR_NAME (&temp) = vro->op0;
-      temp.id = lookup_expression_id (&temp);
-      if (temp.id == 0)
-	return false;
-      if (!union_contains_value (set1, set2,
-				 get_expr_value_id (&temp)))
+      unsigned int value_id = VN_INFO (op)->value_id;
+      if (!(bitmap_set_contains_value (set1, value_id)
+	    || (set2 && bitmap_set_contains_value  (set2, value_id))))
 	return false;
     }
-  if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
-    {
-      struct pre_expr_d temp;
-      temp.kind = NAME;
-      temp.id = 0;
-      PRE_EXPR_NAME (&temp) = vro->op1;
-      temp.id = lookup_expression_id (&temp);
-      if (temp.id == 0)
-	return false;
-      if (!union_contains_value (set1, set2,
-				 get_expr_value_id (&temp)))
-	return false;
-    }
-
-  if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
-    {
-      struct pre_expr_d temp;
-      temp.kind = NAME;
-      temp.id = 0;
-      PRE_EXPR_NAME (&temp) = vro->op2;
-      temp.id = lookup_expression_id (&temp);
-      if (temp.id == 0)
-	return false;
-      if (!union_contains_value (set1, set2,
-				 get_expr_value_id (&temp)))
-	return false;
-    }
-
   return true;
 }
 
@@ -2113,40 +1909,21 @@
    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_set_contains_expr (AVAIL_OUT (block), expr);
+      /* 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;
 	vn_nary_op_t nary = PRE_EXPR_NARY (expr);
 	for (i = 0; i < nary->length; i++)
-	  {
-	    if (TREE_CODE (nary->op[i]) == SSA_NAME)
-	      {
-		struct pre_expr_d temp;
-		temp.kind = NAME;
-		temp.id = 0;
-		PRE_EXPR_NAME (&temp) = nary->op[i];
-		temp.id = lookup_expression_id (&temp);
-		if (temp.id == 0)
-		  return false;
-		if (!union_contains_value (set1, set2,
-					   get_expr_value_id (&temp)))
-		  return false;
-	      }
-	  }
-	/* If the NARY may trap make sure the block does not contain
-	   a possible exit point.
-	   ???  This is overly conservative if we translate AVAIL_OUT
-	   as the available expression might be after the exit point.  */
-	if (BB_MAY_NOTRETURN (block)
-	    && vn_nary_may_trap (nary))
-	  return false;
+	  if (!op_valid_in_sets (set1, set2, nary->op[i]))
+	    return false;
 	return true;
       }
       break;
@@ -2156,94 +1933,94 @@
 	vn_reference_op_t vro;
 	unsigned int i;
 
-	FOR_EACH_VEC_ELT (vn_reference_op_s, ref->operands, i, vro)
+	FOR_EACH_VEC_ELT (ref->operands, i, vro)
 	  {
-	    if (!vro_valid_in_sets (set1, set2, vro))
+	    if (!op_valid_in_sets (set1, set2, vro->op0)
+		|| !op_valid_in_sets (set1, set2, vro->op1)
+		|| !op_valid_in_sets (set1, set2, vro->op2))
 	      return false;
 	  }
-	if (ref->vuse)
-	  {
-	    gimple def_stmt = SSA_NAME_DEF_STMT (ref->vuse);
-	    if (!gimple_nop_p (def_stmt)
-		&& gimple_bb (def_stmt) != block
-		&& !dominated_by_p (CDI_DOMINATORS,
-				    block, gimple_bb (def_stmt)))
-	      return false;
-	  }
-	return !value_dies_in_block_x (expr, block);
+	return true;
       }
     default:
       gcc_unreachable ();
     }
 }
 
-/* Clean the set of expressions that are no longer valid in SET1 or
-   SET2.  This means expressions that are made up of values we have no
-   leaders for in SET1 or SET2.  This version is used for partial
-   anticipation, which means it is not valid in either ANTIC_IN or
-   PA_IN.  */
+/* Clean the set of expressions SET1 that are no longer valid in SET1 or SET2.
+   This means expressions that are made up of values we have no leaders for
+   in SET1 or SET2.  */
 
 static void
-dependent_clean (bitmap_set_t set1, bitmap_set_t set2, basic_block block)
+clean (bitmap_set_t set1, bitmap_set_t set2 = NULL)
 {
-  VEC (pre_expr, heap) *exprs = sorted_array_from_bitmap_set (set1);
+  vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1);
   pre_expr expr;
   int i;
 
-  FOR_EACH_VEC_ELT (pre_expr, exprs, i, expr)
+  FOR_EACH_VEC_ELT (exprs, i, expr)
     {
-      if (!valid_in_sets (set1, set2, expr, block))
-	bitmap_remove_from_set (set1, expr);
+      if (!valid_in_sets (set1, set2, expr))
+	bitmap_remove_expr_from_set (set1, expr);
     }
-  VEC_free (pre_expr, heap, exprs);
+  exprs.release ();
 }
 
-/* Clean the set of expressions that are no longer valid in SET.  This
-   means expressions that are made up of values we have no leaders for
-   in SET.  */
+/* Clean the set of expressions that are no longer valid in SET because
+   they are clobbered in BLOCK or because they trap and may not be executed.  */
 
 static void
-clean (bitmap_set_t set, basic_block block)
+prune_clobbered_mems (bitmap_set_t set, basic_block block)
 {
-  VEC (pre_expr, heap) *exprs = sorted_array_from_bitmap_set (set);
-  pre_expr expr;
-  int i;
-
-  FOR_EACH_VEC_ELT (pre_expr, exprs, i, expr)
+  bitmap_iterator bi;
+  unsigned i;
+  pre_expr to_remove = NULL;
+
+  FOR_EACH_EXPR_ID_IN_SET (set, i, bi)
     {
-      if (!valid_in_sets (set, NULL, expr, block))
-	bitmap_remove_from_set (set, expr);
+      /* Remove queued expr.  */
+      if (to_remove)
+	{
+	  bitmap_remove_expr_from_set (set, to_remove);
+	  to_remove = NULL;
+	}
+
+      pre_expr expr = expression_for_id (i);
+      if (expr->kind == REFERENCE)
+	{
+	  vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
+	  if (ref->vuse)
+	    {
+	      gimple *def_stmt = SSA_NAME_DEF_STMT (ref->vuse);
+	      if (!gimple_nop_p (def_stmt)
+		  && ((gimple_bb (def_stmt) != block
+		       && !dominated_by_p (CDI_DOMINATORS,
+					   block, gimple_bb (def_stmt)))
+		      || (gimple_bb (def_stmt) == block
+			  && value_dies_in_block_x (expr, block))))
+		to_remove = expr;
+	    }
+	}
+      else if (expr->kind == NARY)
+	{
+	  vn_nary_op_t nary = PRE_EXPR_NARY (expr);
+	  /* If the NARY may trap make sure the block does not contain
+	     a possible exit point.
+	     ???  This is overly conservative if we translate AVAIL_OUT
+	     as the available expression might be after the exit point.  */
+	  if (BB_MAY_NOTRETURN (block)
+	      && vn_nary_may_trap (nary))
+	    to_remove = expr;
+	}
     }
-  VEC_free (pre_expr, heap, exprs);
+
+  /* Remove queued expr.  */
+  if (to_remove)
+    bitmap_remove_expr_from_set (set, to_remove);
 }
 
 static sbitmap has_abnormal_preds;
 
-/* List of blocks that may have changed during ANTIC computation and
-   thus need to be iterated over.  */
-
-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))
-    {
-      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
@@ -2257,15 +2034,15 @@
 static bool
 compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
 {
-  bool changed = false;
   bitmap_set_t S, old, ANTIC_OUT;
   bitmap_iterator bi;
   unsigned int bii;
   edge e;
   edge_iterator ei;
 
+  bool changed = ! BB_VISITED (block);
+  BB_VISITED (block) = 1;
   old = ANTIC_OUT = S = NULL;
-  BB_VISITED (block) = 1;
 
   /* If any edges from predecessors are abnormal, antic_in is empty,
      so do nothing.  */
@@ -2283,87 +2060,104 @@
   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, heap) * worklist;
       size_t i;
       basic_block bprime, first = NULL;
 
-      worklist = VEC_alloc (basic_block, heap, EDGE_COUNT (block->succs));
+      auto_vec<basic_block> worklist (EDGE_COUNT (block->succs));
       FOR_EACH_EDGE (e, ei, block->succs)
 	{
 	  if (!first
 	      && BB_VISITED (e->dest))
 	    first = e->dest;
 	  else if (BB_VISITED (e->dest))
-	    VEC_quick_push (basic_block, worklist, e->dest);
+	    worklist.quick_push (e->dest);
+	  else
+	    {
+	      /* Unvisited successors get their ANTIC_IN replaced by the
+		 maximal set to arrive at a maximum ANTIC_IN solution.
+		 We can ignore them in the intersection operation and thus
+		 need not explicitely represent that maximum solution.  */
+	      if (dump_file && (dump_flags & TDF_DETAILS))
+		fprintf (dump_file, "ANTIC_IN is MAX on %d->%d\n",
+			 e->src->index, e->dest->index);
+	    }
 	}
 
-      /* Of multiple successors we have to have visited one already.  */
-      if (!first)
-	{
-	  SET_BIT (changed_blocks, block->index);
-	  BB_VISITED (block) = 0;
-	  BB_DEFERRED (block) = 1;
-	  changed = true;
-	  VEC_free (basic_block, heap, worklist);
-	  goto maybe_dump_sets;
-	}
-
-      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));
-
-      FOR_EACH_VEC_ELT (basic_block, worklist, i, bprime)
+      /* Of multiple successors we have to have visited one already
+         which is guaranteed by iteration order.  */
+      gcc_assert (first != NULL);
+
+      phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first);
+
+      /* If we have multiple successors we need to intersect the ANTIC_OUT
+         sets.  For values that's a simple intersection but for
+	 expressions it is a union.  Given we want to have a single
+	 expression per value in our sets we have to canonicalize.
+	 Avoid randomness and running into cycles like for PR82129 and
+	 canonicalize the expression we choose to the one with the
+	 lowest id.  This requires we actually compute the union first.  */
+      FOR_EACH_VEC_ELT (worklist, i, bprime)
 	{
 	  if (!gimple_seq_empty_p (phi_nodes (bprime)))
 	    {
 	      bitmap_set_t tmp = bitmap_set_new ();
 	      phi_translate_set (tmp, ANTIC_IN (bprime), block, bprime);
-	      bitmap_set_and (ANTIC_OUT, tmp);
+	      bitmap_and_into (&ANTIC_OUT->values, &tmp->values);
+	      bitmap_ior_into (&ANTIC_OUT->expressions, &tmp->expressions);
 	      bitmap_set_free (tmp);
 	    }
 	  else
-	    bitmap_set_and (ANTIC_OUT, ANTIC_IN (bprime));
+	    {
+	      bitmap_and_into (&ANTIC_OUT->values, &ANTIC_IN (bprime)->values);
+	      bitmap_ior_into (&ANTIC_OUT->expressions,
+			       &ANTIC_IN (bprime)->expressions);
+	    }
 	}
-      VEC_free (basic_block, heap, worklist);
+      if (! worklist.is_empty ())
+	{
+	  /* Prune expressions not in the value set, canonicalizing to
+	     expression with lowest ID.  */
+	  bitmap_iterator bi;
+	  unsigned int i;
+	  unsigned int to_clear = -1U;
+	  bitmap seen_value = BITMAP_ALLOC (NULL);
+	  FOR_EACH_EXPR_ID_IN_SET (ANTIC_OUT, i, bi)
+	    {
+	      if (to_clear != -1U)
+		{
+		  bitmap_clear_bit (&ANTIC_OUT->expressions, to_clear);
+		  to_clear = -1U;
+		}
+	      pre_expr expr = expression_for_id (i);
+	      unsigned int value_id = get_expr_value_id (expr);
+	      if (!bitmap_bit_p (&ANTIC_OUT->values, value_id)
+		  || !bitmap_set_bit (seen_value, value_id))
+		to_clear = i;
+	    }
+	  if (to_clear != -1U)
+	    bitmap_clear_bit (&ANTIC_OUT->expressions, to_clear);
+	  BITMAP_FREE (seen_value);
+	}
     }
 
+  /* Prune expressions that are clobbered in block and thus become
+     invalid if translated from ANTIC_OUT to ANTIC_IN.  */
+  prune_clobbered_mems (ANTIC_OUT, block);
+
   /* Generate ANTIC_OUT - TMP_GEN.  */
-  S = bitmap_set_subtract (ANTIC_OUT, TMP_GEN (block));
+  S = bitmap_set_subtract_expressions (ANTIC_OUT, TMP_GEN (block));
 
   /* Start ANTIC_IN with EXP_GEN - TMP_GEN.  */
-  ANTIC_IN (block) = bitmap_set_subtract (EXP_GEN (block),
-					  TMP_GEN (block));
+  ANTIC_IN (block) = bitmap_set_subtract_expressions (EXP_GEN (block),
+						      TMP_GEN (block));
 
   /* Then union in the ANTIC_OUT - TMP_GEN values,
      to get ANTIC_OUT U EXP_GEN - TMP_GEN */
@@ -2371,38 +2165,24 @@
     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)))
-    {
-      changed = true;
-      SET_BIT (changed_blocks, block->index);
-      FOR_EACH_EDGE (e, ei, block->preds)
-	SET_BIT (changed_blocks, e->src->index);
-    }
-  else
-    RESET_BIT (changed_blocks, block->index);
+    changed = true;
 
  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);
-
-	  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 (ANTIC_OUT)
+	print_bitmap_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index);
+
+      if (changed)
+	fprintf (dump_file, "[changed] ");
+      print_bitmap_set (dump_file, ANTIC_IN (block), "ANTIC_IN",
+			block->index);
+
+      if (S)
+	print_bitmap_set (dump_file, S, "S", block->index);
     }
   if (old)
     bitmap_set_free (old);
@@ -2421,15 +2201,13 @@
    else if succs(BLOCK) == 1 then
      PA_OUT[BLOCK] = phi_translate (PA_IN[succ(BLOCK)])
 
-   PA_IN[BLOCK] = dependent_clean(PA_OUT[BLOCK] - TMP_GEN[BLOCK]
-				  - ANTIC_IN[BLOCK])
+   PA_IN[BLOCK] = clean(PA_OUT[BLOCK] - TMP_GEN[BLOCK] - ANTIC_IN[BLOCK])
 
 */
-static bool
+static void
 compute_partial_antic_aux (basic_block block,
 			   bool block_has_abnormal_pred_edge)
 {
-  bool changed = false;
   bitmap_set_t old_PA_IN;
   bitmap_set_t PA_OUT;
   edge e;
@@ -2473,20 +2251,19 @@
      them.  */
   else
     {
-      VEC(basic_block, heap) * worklist;
       size_t i;
       basic_block bprime;
 
-      worklist = VEC_alloc (basic_block, heap, 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)
 	    continue;
-	  VEC_quick_push (basic_block, worklist, e->dest);
+	  worklist.quick_push (e->dest);
 	}
-      if (VEC_length (basic_block, worklist) > 0)
+      if (worklist.length () > 0)
 	{
-	  FOR_EACH_VEC_ELT (basic_block, worklist, i, bprime)
+	  FOR_EACH_VEC_ELT (worklist, i, bprime)
 	    {
 	      unsigned int i;
 	      bitmap_iterator bi;
@@ -2509,12 +2286,15 @@
 						expression_for_id (i));
 	    }
 	}
-      VEC_free (basic_block, heap, worklist);
     }
 
+  /* Prune expressions that are clobbered in block and thus become
+     invalid if translated from PA_OUT to PA_IN.  */
+  prune_clobbered_mems (PA_OUT, block);
+
   /* PA_IN starts with PA_OUT - TMP_GEN.
      Then we subtract things from ANTIC_IN.  */
-  PA_IN (block) = bitmap_set_subtract (PA_OUT, TMP_GEN (block));
+  PA_IN (block) = bitmap_set_subtract_expressions (PA_OUT, TMP_GEN (block));
 
   /* For partial antic, we want to put back in the phi results, since
      we will properly avoid making them partially antic over backedges.  */
@@ -2524,17 +2304,7 @@
   /* 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);
-
-  if (!bitmap_set_equal (old_PA_IN, PA_IN (block)))
-    {
-      changed = true;
-      SET_BIT (changed_blocks, block->index);
-      FOR_EACH_EDGE (e, ei, block->preds)
-	SET_BIT (changed_blocks, e->src->index);
-    }
-  else
-    RESET_BIT (changed_blocks, block->index);
+  clean (PA_IN (block), ANTIC_IN (block));
 
  maybe_dump_sets:
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2548,7 +2318,6 @@
     bitmap_set_free (old_PA_IN);
   if (PA_OUT)
     bitmap_set_free (PA_OUT);
-  return changed;
 }
 
 /* Compute ANTIC and partial ANTIC sets.  */
@@ -2560,42 +2329,44 @@
   int num_iterations = 0;
   basic_block block;
   int i;
+  edge_iterator ei;
+  edge e;
 
   /* 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);
-  sbitmap_zero (has_abnormal_preds);
-
-  FOR_EACH_BB (block)
+  has_abnormal_preds = sbitmap_alloc (last_basic_block_for_fn (cfun));
+  bitmap_clear (has_abnormal_preds);
+
+  FOR_ALL_BB_FN (block, cfun)
     {
-      edge_iterator ei;
-      edge e;
+      BB_VISITED (block) = 0;
 
       FOR_EACH_EDGE (e, ei, block->preds)
-	{
-	  e->flags &= ~EDGE_DFS_BACK;
-	  if (e->flags & EDGE_ABNORMAL)
-	    {
-	      SET_BIT (has_abnormal_preds, block->index);
-	      break;
-	    }
-	}
-
-      BB_VISITED (block) = 0;
-      BB_DEFERRED (block) = 0;
+	if (e->flags & EDGE_ABNORMAL)
+	  {
+	    bitmap_set_bit (has_abnormal_preds, block->index);
+	    break;
+	  }
 
       /* While we are here, give empty ANTIC_IN sets to each block.  */
       ANTIC_IN (block) = bitmap_set_new ();
-      PA_IN (block) = bitmap_set_new ();
+      if (do_partial_partial)
+	PA_IN (block) = bitmap_set_new ();
     }
 
   /* At the exit block we anticipate nothing.  */
-  ANTIC_IN (EXIT_BLOCK_PTR) = bitmap_set_new ();
-  BB_VISITED (EXIT_BLOCK_PTR) = 1;
-  PA_IN (EXIT_BLOCK_PTR) = bitmap_set_new ();
-
-  changed_blocks = sbitmap_alloc (last_basic_block + 1);
-  sbitmap_ones (changed_blocks);
+  BB_VISITED (EXIT_BLOCK_PTR_FOR_FN (cfun)) = 1;
+
+  /* For ANTIC computation we need a postorder that also guarantees that
+     a block with a single successor is visited after its successor.
+     RPO on the inverted CFG has this property.  */
+  auto_vec<int, 20> postorder;
+  inverted_post_order_compute (&postorder);
+
+  auto_sbitmap worklist (last_basic_block_for_fn (cfun) + 1);
+  bitmap_clear (worklist);
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
+    bitmap_set_bit (worklist, e->src->index);
   while (changed)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2606,14 +2377,20 @@
 	 for PA ANTIC computation.  */
       num_iterations++;
       changed = false;
-      for (i = n_basic_blocks - NUM_FIXED_BLOCKS - 1; i >= 0; i--)
+      for (i = postorder.length () - 1; i >= 0; i--)
 	{
-	  if (TEST_BIT (changed_blocks, postorder[i]))
+	  if (bitmap_bit_p (worklist, postorder[i]))
 	    {
-	      basic_block block = BASIC_BLOCK (postorder[i]);
-	      changed |= compute_antic_aux (block,
-					    TEST_BIT (has_abnormal_preds,
-						      block->index));
+	      basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
+	      bitmap_clear_bit (worklist, block->index);
+	      if (compute_antic_aux (block,
+				     bitmap_bit_p (has_abnormal_preds,
+						   block->index)))
+		{
+		  FOR_EACH_EDGE (e, ei, block->preds)
+		    bitmap_set_bit (worklist, e->src->index);
+		  changed = true;
+		}
 	    }
 	}
       /* Theoretically possible, but *highly* unlikely.  */
@@ -2625,63 +2402,20 @@
 
   if (do_partial_partial)
     {
-      sbitmap_ones (changed_blocks);
-      mark_dfs_back_edges ();
-      num_iterations = 0;
-      changed = true;
-      while (changed)
+      /* For partial antic we ignore backedges and thus we do not need
+         to perform any iteration when we process blocks in postorder.  */
+      int postorder_num
+	= pre_and_rev_post_order_compute (NULL, postorder.address (), false);
+      for (i = postorder_num - 1 ; i >= 0; i--)
 	{
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    fprintf (dump_file, "Starting iteration %d\n", num_iterations);
-	  num_iterations++;
-	  changed = false;
-	  for (i = n_basic_blocks - NUM_FIXED_BLOCKS - 1 ; i >= 0; i--)
-	    {
-	      if (TEST_BIT (changed_blocks, postorder[i]))
-		{
-		  basic_block block = BASIC_BLOCK (postorder[i]);
-		  changed
-		    |= compute_partial_antic_aux (block,
-						  TEST_BIT (has_abnormal_preds,
-							    block->index));
-		}
-	    }
-	  /* Theoretically possible, but *highly* unlikely.  */
-	  gcc_checking_assert (num_iterations < 500);
+	  basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
+	  compute_partial_antic_aux (block,
+				     bitmap_bit_p (has_abnormal_preds,
+						   block->index));
 	}
-      statistics_histogram_event (cfun, "compute_partial_antic iterations",
-				  num_iterations);
     }
+
   sbitmap_free (has_abnormal_preds);
-  sbitmap_free (changed_blocks);
-}
-
-/* Return true if we can value number the call in STMT.  This is true
-   if we have a pure or constant call.  */
-
-static bool
-can_value_number_call (gimple stmt)
-{
-  if (gimple_call_flags (stmt) & (ECF_PURE | ECF_CONST))
-    return true;
-  return false;
-}
-
-/* Return true if OP is a tree which we can perform PRE on.
-   This may not match the operations we can value number, but in
-   a perfect world would.  */
-
-static bool
-can_PRE_operation (tree op)
-{
-  return UNARY_CLASS_P (op)
-    || BINARY_CLASS_P (op)
-    || COMPARISON_CLASS_P (op)
-    || TREE_CODE (op) == MEM_REF 
-    || TREE_CODE (op) == COMPONENT_REF
-    || TREE_CODE (op) == VIEW_CONVERT_EXPR
-    || TREE_CODE (op) == CALL_EXPR
-    || TREE_CODE (op) == ARRAY_REF;
 }
 
 
@@ -2690,76 +2424,27 @@
    that didn't turn out to be necessary.   */
 static bitmap inserted_exprs;
 
-/* Pool allocated fake store expressions are placed onto this
-   worklist, which, after performing dead code elimination, is walked
-   to see which expressions need to be put into GC'able memory  */
-static VEC(gimple, heap) *need_creation;
-
 /* The actual worker for create_component_ref_by_pieces.  */
 
 static tree
 create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
-				  unsigned int *operand, gimple_seq *stmts,
-				  gimple domstmt)
+				  unsigned int *operand, gimple_seq *stmts)
 {
-  vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
-					*operand);
+  vn_reference_op_t currop = &ref->operands[*operand];
   tree genop;
   ++*operand;
   switch (currop->opcode)
     {
     case CALL_EXPR:
-      {
-	tree folded, sc = NULL_TREE;
-	unsigned int nargs = 0;
-	tree fn, *args;
-	if (TREE_CODE (currop->op0) == FUNCTION_DECL)
-	  fn = currop->op0;
-	else
-	  {
-	    pre_expr op0 = get_or_alloc_expr_for (currop->op0);
-	    fn = find_or_generate_expression (block, op0, stmts, domstmt);
-	    if (!fn)
-	      return NULL_TREE;
-	  }
-	if (currop->op1)
-	  {
-	    pre_expr scexpr = get_or_alloc_expr_for (currop->op1);
-	    sc = find_or_generate_expression (block, scexpr, stmts, domstmt);
-	    if (!sc)
-	      return NULL_TREE;
-	  }
-	args = XNEWVEC (tree, VEC_length (vn_reference_op_s,
-					  ref->operands) - 1);
-	while (*operand < VEC_length (vn_reference_op_s, ref->operands))
-	  {
-	    args[nargs] = create_component_ref_by_pieces_1 (block, ref,
-							    operand, stmts,
-							    domstmt);
-	    if (!args[nargs])
-	      {
-		free (args);
-		return NULL_TREE;
-	      }
-	    nargs++;
-	  }
-	folded = build_call_array (currop->type,
-				   (TREE_CODE (fn) == FUNCTION_DECL
-				    ? build_fold_addr_expr (fn) : fn),
-				   nargs, args);
-	free (args);
-	if (sc)
-	  CALL_EXPR_STATIC_CHAIN (folded) = sc;
-	return folded;
-      }
-      break;
+      gcc_unreachable ();
+
     case MEM_REF:
       {
 	tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
-							stmts, domstmt);
-	tree offset = currop->op0;
+							stmts);
 	if (!baseop)
 	  return NULL_TREE;
+	tree offset = currop->op0;
 	if (TREE_CODE (baseop) == ADDR_EXPR
 	    && handled_component_p (TREE_OPERAND (baseop, 0)))
 	  {
@@ -2770,42 +2455,44 @@
 	    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);
+	genop = build2 (MEM_REF, currop->type, baseop, offset);
+	MR_DEPENDENCE_CLIQUE (genop) = currop->clique;
+	MR_DEPENDENCE_BASE (genop) = currop->base;
+	REF_REVERSE_STORAGE_ORDER (genop) = currop->reverse;
+	return genop;
       }
-      break;
+
     case TARGET_MEM_REF:
       {
-	pre_expr op0expr, op1expr;
 	tree genop0 = NULL_TREE, genop1 = NULL_TREE;
-	vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands,
-					      ++*operand);
+	vn_reference_op_t nextop = &ref->operands[++*operand];
 	tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
-							stmts, domstmt);
+							stmts);
 	if (!baseop)
 	  return NULL_TREE;
 	if (currop->op0)
 	  {
-	    op0expr = get_or_alloc_expr_for (currop->op0);
-	    genop0 = find_or_generate_expression (block, op0expr,
-						  stmts, domstmt);
+	    genop0 = find_or_generate_expression (block, currop->op0, stmts);
 	    if (!genop0)
 	      return NULL_TREE;
 	  }
 	if (nextop->op0)
 	  {
-	    op1expr = get_or_alloc_expr_for (nextop->op0);
-	    genop1 = find_or_generate_expression (block, op1expr,
-						  stmts, domstmt);
+	    genop1 = find_or_generate_expression (block, nextop->op0, stmts);
 	    if (!genop1)
 	      return NULL_TREE;
 	  }
-	return build5 (TARGET_MEM_REF, currop->type,
-		       baseop, currop->op2, genop0, currop->op1, genop1);
+	genop = build5 (TARGET_MEM_REF, currop->type,
+			baseop, currop->op2, genop0, currop->op1, genop1);
+
+	MR_DEPENDENCE_CLIQUE (genop) = currop->clique;
+	MR_DEPENDENCE_BASE (genop) = currop->base;
+	return genop;
       }
-      break;
+
     case ADDR_EXPR:
       if (currop->op0)
 	{
@@ -2817,38 +2504,36 @@
     case IMAGPART_EXPR:
     case VIEW_CONVERT_EXPR:
       {
-	tree folded;
-	tree genop0 = create_component_ref_by_pieces_1 (block, ref,
-							operand,
-							stmts, domstmt);
+	tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
+							stmts);
 	if (!genop0)
 	  return NULL_TREE;
-	folded = fold_build1 (currop->opcode, currop->type,
-			      genop0);
-	return folded;
+	return fold_build1 (currop->opcode, currop->type, genop0);
       }
-      break;
+
+    case WITH_SIZE_EXPR:
+      {
+	tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
+							stmts);
+	if (!genop0)
+	  return NULL_TREE;
+	tree genop1 = find_or_generate_expression (block, currop->op0, stmts);
+	if (!genop1)
+	  return NULL_TREE;
+	return fold_build2 (currop->opcode, currop->type, genop0, genop1);
+      }
+
     case BIT_FIELD_REF:
       {
-	tree folded;
 	tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
-							stmts, domstmt);
-	pre_expr op1expr = get_or_alloc_expr_for (currop->op0);
-	pre_expr op2expr = get_or_alloc_expr_for (currop->op1);
-	tree genop1;
-	tree genop2;
-
+							stmts);
 	if (!genop0)
 	  return NULL_TREE;
-	genop1 = find_or_generate_expression (block, op1expr, stmts, domstmt);
-	if (!genop1)
-	  return NULL_TREE;
-	genop2 = find_or_generate_expression (block, op2expr, stmts, domstmt);
-	if (!genop2)
-	  return NULL_TREE;
-	folded = fold_build3 (BIT_FIELD_REF, currop->type, genop0, genop1,
-			      genop2);
-	return folded;
+	tree op1 = currop->op0;
+	tree op2 = currop->op1;
+	tree t = build3 (BIT_FIELD_REF, currop->type, genop0, op1, op2);
+	REF_REVERSE_STORAGE_ORDER (t) = currop->reverse;
+	return fold (t);
       }
 
       /* For array ref vn_reference_op's, operand 1 of the array ref
@@ -2859,29 +2544,26 @@
       {
 	tree genop0;
 	tree genop1 = currop->op0;
-	pre_expr op1expr;
 	tree genop2 = currop->op1;
-	pre_expr op2expr;
 	tree genop3 = currop->op2;
-	pre_expr op3expr;
 	genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
-						   stmts, domstmt);
+						   stmts);
 	if (!genop0)
 	  return NULL_TREE;
-	op1expr = get_or_alloc_expr_for (genop1);
-	genop1 = find_or_generate_expression (block, op1expr, stmts, domstmt);
+	genop1 = find_or_generate_expression (block, genop1, stmts);
 	if (!genop1)
 	  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
 	      {
-		op2expr = get_or_alloc_expr_for (genop2);
-		genop2 = find_or_generate_expression (block, op2expr, stmts,
-						      domstmt);
+		genop2 = find_or_generate_expression (block, genop2, stmts);
 		if (!genop2)
 		  return NULL_TREE;
 	      }
@@ -2893,15 +2575,15 @@
 	       here as the element alignment may be not visible.  See
 	       PR43783.  Simply drop the element size for constant
 	       sizes.  */
-	    if (tree_int_cst_equal (genop3, TYPE_SIZE_UNIT (elmt_type)))
+	    if (TREE_CODE (genop3) == INTEGER_CST
+		&& TREE_CODE (TYPE_SIZE_UNIT (elmt_type)) == INTEGER_CST
+		&& wi::eq_p (wi::to_offset (TYPE_SIZE_UNIT (elmt_type)),
+			     (wi::to_offset (genop3)
+			      * vn_ref_op_align_unit (currop))))
 	      genop3 = NULL_TREE;
 	    else
 	      {
-		genop3 = size_binop (EXACT_DIV_EXPR, genop3,
-				     size_int (TYPE_ALIGN_UNIT (elmt_type)));
-		op3expr = get_or_alloc_expr_for (genop3);
-		genop3 = find_or_generate_expression (block, op3expr, stmts,
-						      domstmt);
+		genop3 = find_or_generate_expression (block, genop3, stmts);
 		if (!genop3)
 		  return NULL_TREE;
 	      }
@@ -2914,31 +2596,23 @@
 	tree op0;
 	tree op1;
 	tree genop2 = currop->op1;
-	pre_expr op2expr;
-	op0 = create_component_ref_by_pieces_1 (block, ref, operand,
-						stmts, domstmt);
+	op0 = create_component_ref_by_pieces_1 (block, ref, operand, stmts);
 	if (!op0)
 	  return NULL_TREE;
-	/* op1 should be a FIELD_DECL, which are represented by
-	   themselves.  */
+	/* op1 should be a FIELD_DECL, which are represented by themselves.  */
 	op1 = currop->op0;
 	if (genop2)
 	  {
-	    op2expr = get_or_alloc_expr_for (genop2);
-	    genop2 = find_or_generate_expression (block, op2expr, stmts,
-						  domstmt);
+	    genop2 = find_or_generate_expression (block, genop2, stmts);
 	    if (!genop2)
 	      return NULL_TREE;
 	  }
-
-	return fold_build3 (COMPONENT_REF, TREE_TYPE (op1), op0, op1,
-			    genop2);
+	return fold_build3 (COMPONENT_REF, TREE_TYPE (op1), op0, op1, genop2);
       }
-      break;
+
     case SSA_NAME:
       {
-	pre_expr op0expr = get_or_alloc_expr_for (currop->op0);
-	genop = find_or_generate_expression (block, op0expr, stmts, domstmt);
+	genop = find_or_generate_expression (block, currop->op0, stmts);
 	return genop;
       }
     case STRING_CST:
@@ -2973,75 +2647,56 @@
 
 static tree
 create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
-				gimple_seq *stmts, gimple domstmt)
+				gimple_seq *stmts)
 {
   unsigned int op = 0;
-  return create_component_ref_by_pieces_1 (block, ref, &op, stmts, domstmt);
+  return create_component_ref_by_pieces_1 (block, ref, &op, stmts);
 }
 
-/* Find a leader for an expression, or generate one using
-   create_expression_by_pieces if it's ANTIC but
-   complex.
+/* Find a simple leader for an expression, or generate one using
+   create_expression_by_pieces from a NARY expression for the value.
    BLOCK is the basic_block we are looking for leaders in.
-   EXPR is the expression to find a leader or generate for.
-   STMTS is the statement list to put the inserted expressions on.
-   Returns the SSA_NAME of the LHS of the generated expression or the
-   leader.
-   DOMSTMT if non-NULL is a statement that should be dominated by
-   all uses in the generated expression.  If DOMSTMT is non-NULL this
-   routine can fail and return NULL_TREE.  Otherwise it will assert
-   on failure.  */
+   OP is the tree expression to find a leader for or generate.
+   Returns the leader or NULL_TREE on failure.  */
 
 static tree
-find_or_generate_expression (basic_block block, pre_expr expr,
-			     gimple_seq *stmts, gimple domstmt)
+find_or_generate_expression (basic_block block, tree op, gimple_seq *stmts)
 {
-  pre_expr leader = bitmap_find_leader (AVAIL_OUT (block),
-					get_expr_value_id (expr), domstmt);
-  tree genop = NULL;
+  pre_expr expr = get_or_alloc_expr_for (op);
+  unsigned int lookfor = get_expr_value_id (expr);
+  pre_expr leader = bitmap_find_leader (AVAIL_OUT (block), lookfor);
   if (leader)
     {
       if (leader->kind == NAME)
-	genop = PRE_EXPR_NAME (leader);
+	return PRE_EXPR_NAME (leader);
       else if (leader->kind == CONSTANT)
-	genop = PRE_EXPR_CONSTANT (leader);
+	return PRE_EXPR_CONSTANT (leader);
+
+      /* Defer.  */
+      return NULL_TREE;
     }
 
-  /* If it's still NULL, it must be a complex expression, so generate
-     it recursively.  Not so if inserting expressions for values generated
-     by SCCVN.  */
-  if (genop == NULL
-      && !domstmt)
+  /* It must be a complex expression, so generate it recursively.  Note
+     that this is only necessary to handle gcc.dg/tree-ssa/ssa-pre28.c
+     where the insert algorithm fails to insert a required expression.  */
+  bitmap exprset = value_expressions[lookfor];
+  bitmap_iterator bi;
+  unsigned int i;
+  EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
     {
-      bitmap_set_t exprset;
-      unsigned int lookfor = get_expr_value_id (expr);
-      bool handled = false;
-      bitmap_iterator bi;
-      unsigned int i;
-
-      exprset = VEC_index (bitmap_set_t, value_expressions, lookfor);
-      FOR_EACH_EXPR_ID_IN_SET (exprset, i, bi)
-	{
-	  pre_expr temp = expression_for_id (i);
-	  if (temp->kind != NAME)
-	    {
-	      handled = true;
-	      genop = create_expression_by_pieces (block, temp, stmts,
-						   domstmt,
-						   get_expr_type (expr));
-	      break;
-	    }
-	}
-      if (!handled && domstmt)
-	return NULL_TREE;
-
-      gcc_assert (handled);
+      pre_expr temp = expression_for_id (i);
+      /* We cannot insert random REFERENCE expressions at arbitrary
+	 places.  We can insert NARYs which eventually re-materializes
+	 its operand values.  */
+      if (temp->kind == NARY)
+	return create_expression_by_pieces (block, temp, stmts,
+					    get_expr_type (expr));
     }
-  return genop;
+
+  /* Defer.  */
+  return NULL_TREE;
 }
 
-#define NECESSARY GF_PLF_1
-
 /* Create an expression in pieces, so that we can handle very complex
    expressions that may be ANTIC, but not necessary GIMPLE.
    BLOCK is the basic block the expression will be inserted into,
@@ -3050,108 +2705,192 @@
 
    This function will die if we hit some value that shouldn't be
    ANTIC but is (IE there is no leader for it, or its components).
+   The function returns NULL_TREE in case a different antic expression
+   has to be inserted first.
    This function may also generate expressions that are themselves
    partially or fully redundant.  Those that are will be either made
    fully redundant during the next iteration of insert (for partially
    redundant ones), or eliminated by eliminate (for fully redundant
-   ones).
-
-   If DOMSTMT is non-NULL then we make sure that all uses in the
-   expressions dominate that statement.  In this case the function
-   can return NULL_TREE to signal failure.  */
+   ones).  */
 
 static tree
 create_expression_by_pieces (basic_block block, pre_expr expr,
-			     gimple_seq *stmts, gimple domstmt, tree type)
+			     gimple_seq *stmts, tree type)
 {
-  tree temp, name;
+  tree name;
   tree folded;
   gimple_seq forced_stmts = NULL;
   unsigned int value_id;
   gimple_stmt_iterator gsi;
   tree exprtype = type ? type : get_expr_type (expr);
   pre_expr nameexpr;
-  gimple newstmt;
+  gassign *newstmt;
 
   switch (expr->kind)
     {
-      /* We may hit the NAME/CONSTANT case if we have to convert types
-	 that value numbering saw through.  */
+    /* We may hit the NAME/CONSTANT case if we have to convert types
+       that value numbering saw through.  */
     case NAME:
       folded = PRE_EXPR_NAME (expr);
+      if (useless_type_conversion_p (exprtype, TREE_TYPE (folded)))
+	return folded;
       break;
     case CONSTANT:
-      folded = PRE_EXPR_CONSTANT (expr);
-      break;
+      { 
+	folded = PRE_EXPR_CONSTANT (expr);
+	tree tem = fold_convert (exprtype, folded);
+	if (is_gimple_min_invariant (tem))
+	  return tem;
+	break;
+      }
     case REFERENCE:
-      {
-	vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
-	folded = create_component_ref_by_pieces (block, ref, stmts, domstmt);
-      }
+      if (PRE_EXPR_REFERENCE (expr)->operands[0].opcode == CALL_EXPR)
+	{
+	  vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
+	  unsigned int operand = 1;
+	  vn_reference_op_t currop = &ref->operands[0];
+	  tree sc = NULL_TREE;
+	  tree fn;
+	  if (TREE_CODE (currop->op0) == FUNCTION_DECL)
+	    fn = currop->op0;
+	  else
+	    fn = find_or_generate_expression (block, currop->op0, stmts);
+	  if (!fn)
+	    return NULL_TREE;
+	  if (currop->op1)
+	    {
+	      sc = find_or_generate_expression (block, currop->op1, stmts);
+	      if (!sc)
+		return NULL_TREE;
+	    }
+	  auto_vec<tree> args (ref->operands.length () - 1);
+	  while (operand < ref->operands.length ())
+	    {
+	      tree arg = create_component_ref_by_pieces_1 (block, ref,
+							   &operand, stmts);
+	      if (!arg)
+		return NULL_TREE;
+	      args.quick_push (arg);
+	    }
+	  gcall *call
+	    = gimple_build_call_vec ((TREE_CODE (fn) == FUNCTION_DECL
+				      ? build_fold_addr_expr (fn) : fn), args);
+	  gimple_call_set_with_bounds (call, currop->with_bounds);
+	  if (sc)
+	    gimple_call_set_chain (call, sc);
+	  tree forcedname = make_ssa_name (currop->type);
+	  gimple_call_set_lhs (call, forcedname);
+	  gimple_set_vuse (call, BB_LIVE_VOP_ON_EXIT (block));
+	  gimple_seq_add_stmt_without_update (&forced_stmts, call);
+	  folded = forcedname;
+	}
+      else
+	{
+	  folded = create_component_ref_by_pieces (block,
+						   PRE_EXPR_REFERENCE (expr),
+						   stmts);
+	  if (!folded)
+	    return NULL_TREE;
+	  name = make_temp_ssa_name (exprtype, NULL, "pretmp");
+	  newstmt = gimple_build_assign (name, folded);
+	  gimple_seq_add_stmt_without_update (&forced_stmts, newstmt);
+	  gimple_set_vuse (newstmt, BB_LIVE_VOP_ON_EXIT (block));
+	  folded = name;
+	}
       break;
     case NARY:
       {
 	vn_nary_op_t nary = PRE_EXPR_NARY (expr);
-	switch (nary->length)
+	tree *genop = XALLOCAVEC (tree, nary->length);
+	unsigned i;
+	for (i = 0; i < nary->length; ++i)
+	  {
+	    genop[i] = find_or_generate_expression (block, nary->op[i], stmts);
+	    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] = gimple_convert (&forced_stmts,
+					     nary->type, genop[i]);
+		else if (i == 1)
+		  genop[i] = gimple_convert (&forced_stmts,
+					     sizetype, genop[i]);
+	      }
+	    else
+	      genop[i] = gimple_convert (&forced_stmts,
+					 TREE_TYPE (nary->op[i]), genop[i]);
+	  }
+	if (nary->opcode == CONSTRUCTOR)
 	  {
-	  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;
+	    vec<constructor_elt, va_gc> *elts = NULL;
+	    for (i = 0; i < nary->length; ++i)
+	      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, genop[i]);
+	    folded = build_constructor (nary->type, elts);
+	    name = make_temp_ssa_name (exprtype, NULL, "pretmp");
+	    newstmt = gimple_build_assign (name, folded);
+	    gimple_seq_add_stmt_without_update (&forced_stmts, newstmt);
+	    folded = name;
+	  }
+	else
+	  {
+	    switch (nary->length)
+	      {
+	      case 1:
+		folded = gimple_build (&forced_stmts, nary->opcode, nary->type,
+				       genop[0]);
+		break;
+	      case 2:
+		folded = gimple_build (&forced_stmts, nary->opcode, nary->type,
+				       genop[0], genop[1]);
+		break;
+	      case 3:
+		folded = gimple_build (&forced_stmts, nary->opcode, nary->type,
+				       genop[0], genop[1], genop[2]);
+		break;
+	      default:
+		gcc_unreachable ();
+	      }
 	  }
       }
       break;
     default:
-      return NULL_TREE;
+      gcc_unreachable ();
+    }
+
+  folded = gimple_convert (&forced_stmts, exprtype, folded);
+
+  /* If there is nothing to insert, return the simplified result.  */
+  if (gimple_seq_empty_p (forced_stmts))
+    return folded;
+  /* If we simplified to a constant return it and discard eventually
+     built stmts.  */
+  if (is_gimple_min_invariant (folded))
+    {
+      gimple_seq_discard (forced_stmts);
+      return folded;
     }
-
-  if (!useless_type_conversion_p (exprtype, TREE_TYPE (folded)))
-    folded = fold_convert (exprtype, folded);
-
-  /* Force the generated expression to be a sequence of GIMPLE
-     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,
-				 false, NULL);
+  /* Likewise if we simplified to sth not queued for insertion.  */
+  bool found = false;
+  gsi = gsi_last (forced_stmts);
+  for (; !gsi_end_p (gsi); gsi_prev (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      tree forcedname = gimple_get_lhs (stmt);
+      if (forcedname == folded)
+	{
+	  found = true;
+	  break;
+	}
+    }
+  if (! found)
+    {
+      gimple_seq_discard (forced_stmts);
+      return folded;
+    }
+  gcc_assert (TREE_CODE (folded) == SSA_NAME);
 
   /* If we have any intermediate expressions to the value sets, add them
      to the value sets and chain them in the instruction stream.  */
@@ -3160,56 +2899,43 @@
       gsi = gsi_start (forced_stmts);
       for (; !gsi_end_p (gsi); gsi_next (&gsi))
 	{
-	  gimple stmt = gsi_stmt (gsi);
+	  gimple *stmt = gsi_stmt (gsi);
 	  tree forcedname = gimple_get_lhs (stmt);
 	  pre_expr nameexpr;
 
-	  if (TREE_CODE (forcedname) == SSA_NAME)
+	  if (forcedname != folded)
 	    {
-	      bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (forcedname));
 	      VN_INFO_GET (forcedname)->valnum = forcedname;
 	      VN_INFO (forcedname)->value_id = get_next_value_id ();
 	      nameexpr = get_or_alloc_expr_for_name (forcedname);
 	      add_to_value (VN_INFO (forcedname)->value_id, nameexpr);
-	      if (!in_fre)
-		bitmap_value_replace_in_set (NEW_SETS (block), nameexpr);
+	      bitmap_value_replace_in_set (NEW_SETS (block), nameexpr);
 	      bitmap_value_replace_in_set (AVAIL_OUT (block), nameexpr);
 	    }
-	  mark_symbols_for_renaming (stmt);
+
+	  bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (forcedname));
 	}
       gimple_seq_add_seq (stmts, forced_stmts);
     }
 
-  /* 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);
-    }
-
-  temp = pretemp;
-  add_referenced_var (temp);
-
-  newstmt = gimple_build_assign (temp, folded);
-  name = make_ssa_name (temp, newstmt);
-  gimple_assign_set_lhs (newstmt, name);
-  gimple_set_plf (newstmt, NECESSARY, false);
-
-  gimple_seq_add_stmt (stmts, newstmt);
-  bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (name));
-
-  /* All the symbols in NEWEXPR should be put into SSA form.  */
-  mark_symbols_for_renaming (newstmt);
+  name = folded;
+
+  /* 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
      the expression may have been represented.  There is no harm in replacing
      here.  */
-  VN_INFO_GET (name)->valnum = name;
   value_id = get_expr_value_id (expr);
-  VN_INFO (name)->value_id = value_id;
+  VN_INFO_GET (name)->value_id = value_id;
+  VN_INFO (name)->valnum = sccvn_valnum_from_value_id (value_id);
+  if (VN_INFO (name)->valnum == NULL_TREE)
+    VN_INFO (name)->valnum = name;
+  gcc_assert (VN_INFO (name)->valnum != NULL_TREE);
   nameexpr = get_or_alloc_expr_for_name (name);
   add_to_value (value_id, nameexpr);
   if (NEW_SETS (block))
@@ -3220,70 +2946,15 @@
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Inserted ");
-      print_gimple_stmt (dump_file, newstmt, 0, 0);
-      fprintf (dump_file, " in predecessor %d\n", block->index);
+      print_gimple_stmt (dump_file, gsi_stmt (gsi_last (*stmts)), 0);
+      fprintf (dump_file, " in predecessor %d (%04d)\n",
+	       block->index, value_id);
     }
 
   return name;
 }
 
 
-/* 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, heap) *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_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 (vn_reference_op_s, ops, i, op)
-    {
-      switch (op->opcode)
-	{
-	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
@@ -3291,7 +2962,7 @@
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    pre_expr *avail)
+			    vec<pre_expr> avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
@@ -3304,17 +2975,10 @@
   edge_iterator ei;
   tree type = get_expr_type (expr);
   tree temp;
-  gimple phi;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "Found partial redundancy for expression ");
-      print_pre_expr (dump_file, expr);
-      fprintf (dump_file, " (%04d)\n", val);
-    }
+  gphi *phi;
 
   /* Make sure we aren't creating an induction variable.  */
-  if (block->loop_depth > 0 && EDGE_COUNT (block->preds) == 2)
+  if (bb_loop_depth (block) > 0 && EDGE_COUNT (block->preds) == 2)
     {
       bool firstinsideloop = false;
       bool secondinsideloop = false;
@@ -3324,8 +2988,7 @@
 						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");
@@ -3339,101 +3002,26 @@
       gimple_seq stmts = NULL;
       tree builtexpr;
       bprime = pred->src;
-      eprime = avail[bprime->index];
-
-      if (eprime->kind != NAME && eprime->kind != CONSTANT)
+      eprime = avail[pred->dest_idx];
+      builtexpr = create_expression_by_pieces (bprime, eprime,
+					       &stmts, type);
+      gcc_assert (!(pred->flags & EDGE_ABNORMAL));
+      if (!gimple_seq_empty_p (stmts))
 	{
-	  builtexpr = create_expression_by_pieces (bprime,
-						   eprime,
-						   &stmts, NULL,
-						   type);
-	  gcc_assert (!(pred->flags & EDGE_ABNORMAL));
 	  gsi_insert_seq_on_edge (pred, stmts);
-	  avail[bprime->index] = get_or_alloc_expr_for_name (builtexpr);
 	  insertions = true;
 	}
-      else if (eprime->kind == CONSTANT)
+      if (!builtexpr)
 	{
-	  /* Constants may not have the right type, fold_convert
-	     should give us back a constant with the right type.
-	  */
-	  tree constant = PRE_EXPR_CONSTANT (eprime);
-	  if (!useless_type_conversion_p (type, TREE_TYPE (constant)))
-	    {
-	      tree builtexpr = fold_convert (type, constant);
-	      if (!is_gimple_min_invariant (builtexpr))
-		{
-		  tree forcedexpr = force_gimple_operand (builtexpr,
-							  &stmts, true,
-							  NULL);
-		  if (!is_gimple_min_invariant (forcedexpr))
-		    {
-		      if (forcedexpr != builtexpr)
-			{
-			  VN_INFO_GET (forcedexpr)->valnum = PRE_EXPR_CONSTANT (eprime);
-			  VN_INFO (forcedexpr)->value_id = get_expr_value_id (eprime);
-			}
-		      if (stmts)
-			{
-			  gimple_stmt_iterator gsi;
-			  gsi = gsi_start (stmts);
-			  for (; !gsi_end_p (gsi); gsi_next (&gsi))
-			    {
-			      gimple stmt = gsi_stmt (gsi);
-			      tree lhs = gimple_get_lhs (stmt);
-			      if (TREE_CODE (lhs) == SSA_NAME)
-				bitmap_set_bit (inserted_exprs,
-						SSA_NAME_VERSION (lhs));
-			      gimple_set_plf (stmt, NECESSARY, false);
-			    }
-			  gsi_insert_seq_on_edge (pred, stmts);
-			}
-		      avail[bprime->index] = get_or_alloc_expr_for_name (forcedexpr);
-		    }
-		}
-	      else
-		avail[bprime->index] = get_or_alloc_expr_for_constant (builtexpr);
-	    }
+	  /* We cannot insert a PHI node if we failed to insert
+	     on one edge.  */
+	  nophi = true;
+	  continue;
 	}
-      else if (eprime->kind == NAME)
-	{
-	  /* We may have to do a conversion because our value
-	     numbering can look through types in certain cases, but
-	     our IL requires all operands of a phi node have the same
-	     type.  */
-	  tree name = PRE_EXPR_NAME (eprime);
-	  if (!useless_type_conversion_p (type, TREE_TYPE (name)))
-	    {
-	      tree builtexpr;
-	      tree forcedexpr;
-	      builtexpr = fold_convert (type, name);
-	      forcedexpr = force_gimple_operand (builtexpr,
-						 &stmts, true,
-						 NULL);
-
-	      if (forcedexpr != name)
-		{
-		  VN_INFO_GET (forcedexpr)->valnum = VN_INFO (name)->valnum;
-		  VN_INFO (forcedexpr)->value_id = VN_INFO (name)->value_id;
-		}
-
-	      if (stmts)
-		{
-		  gimple_stmt_iterator gsi;
-		  gsi = gsi_start (stmts);
-		  for (; !gsi_end_p (gsi); gsi_next (&gsi))
-		    {
-		      gimple stmt = gsi_stmt (gsi);
-		      tree lhs = gimple_get_lhs (stmt);
-		      if (TREE_CODE (lhs) == SSA_NAME)
-			bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
-		      gimple_set_plf (stmt, NECESSARY, false);
-		    }
-		  gsi_insert_seq_on_edge (pred, stmts);
-		}
-	      avail[bprime->index] = get_or_alloc_expr_for_name (forcedexpr);
-	    }
-	}
+      if (is_gimple_min_invariant (builtexpr))
+	avail[pred->dest_idx] = get_or_alloc_expr_for_constant (builtexpr);
+      else
+	avail[pred->dest_idx] = get_or_alloc_expr_for_name (builtexpr);
     }
   /* If we didn't want a phi node, and we made insertions, we still have
      inserted new stuff, and thus return true.  If we didn't want a phi node,
@@ -3445,37 +3033,27 @@
     return false;
 
   /* Now build a phi for the new variable.  */
-  if (!prephitemp || TREE_TYPE (prephitemp) != type)
-    {
-      prephitemp = create_tmp_var (type, "prephitmp");
-      get_var_ann (prephitemp);
-    }
-
-  temp = prephitemp;
-  add_referenced_var (temp);
-
-  if (TREE_CODE (type) == COMPLEX_TYPE
-      || TREE_CODE (type) == VECTOR_TYPE)
-    DECL_GIMPLE_REG_P (temp) = 1;
+  temp = make_temp_ssa_name (type, NULL, "prephitmp");
   phi = create_phi_node (temp, block);
 
-  gimple_set_plf (phi, NECESSARY, false);
-  VN_INFO_GET (gimple_phi_result (phi))->valnum = gimple_phi_result (phi);
-  VN_INFO (gimple_phi_result (phi))->value_id = val;
-  bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (gimple_phi_result (phi)));
+  VN_INFO_GET (temp)->value_id = val;
+  VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
+  if (VN_INFO (temp)->valnum == NULL_TREE)
+    VN_INFO (temp)->valnum = temp;
+  bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (temp));
   FOR_EACH_EDGE (pred, ei, block->preds)
     {
-      pre_expr ae = avail[pred->src->index];
+      pre_expr ae = avail[pred->dest_idx];
       gcc_assert (get_expr_type (ae) == type
 		  || useless_type_conversion_p (type, get_expr_type (ae)));
       if (ae->kind == CONSTANT)
-	add_phi_arg (phi, PRE_EXPR_CONSTANT (ae), pred, UNKNOWN_LOCATION);
+	add_phi_arg (phi, unshare_expr (PRE_EXPR_CONSTANT (ae)),
+		     pred, UNKNOWN_LOCATION);
       else
-	add_phi_arg (phi, PRE_EXPR_NAME (avail[pred->src->index]), pred,
-		     UNKNOWN_LOCATION);
+	add_phi_arg (phi, PRE_EXPR_NAME (ae), pred, UNKNOWN_LOCATION);
     }
 
-  newphi = get_or_alloc_expr_for_name (gimple_phi_result (phi));
+  newphi = get_or_alloc_expr_for_name (temp);
   add_to_value (val, newphi);
 
   /* The value should *not* exist in PHI_GEN, or else we wouldn't be doing
@@ -3498,11 +3076,38 @@
   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 ");
-      print_gimple_stmt (dump_file, phi, 0, 0);
-      fprintf (dump_file, " in block %d\n", block->index);
+      print_gimple_stmt (dump_file, phi, 0);
+      fprintf (dump_file, " in block %d (%04d)\n", block->index, val);
     }
   pre_stats.phis++;
   return true;
@@ -3510,7 +3115,7 @@
 
 
 
-/* Perform insertion of partially redundant values.
+/* Perform insertion of partially redundant or hoistable values.
    For BLOCK, do the following:
    1.  Propagate the NEW_SETS of the dominator into the current block.
    If the block has multiple predecessors,
@@ -3521,26 +3126,35 @@
        2c. Insert a new PHI merging the values of the predecessors.
        2d. Insert the new PHI, and the new expressions, into the
 	   NEW_SETS set.
-   3. Recursively call ourselves on the dominator children of BLOCK.
-
-   Steps 1, 2a, and 3 are done by insert_aux. 2b, 2c and 2d are done by
-   do_regular_insertion and do_partial_insertion.
-
+   If the block has multiple successors,
+       3a. Iterate over the ANTIC values for the block to see if
+	   any of them are good candidates for hoisting.
+       3b. If so, insert expressions computing the values in BLOCK,
+	   and add the new expressions into the NEW_SETS set.
+   4. Recursively call ourselves on the dominator children of BLOCK.
+
+   Steps 1, 2a, and 4 are done by insert_aux. 2b, 2c and 2d are done by
+   do_pre_regular_insertion and do_partial_insertion.  3a and 3b are
+   done in do_hoist_insertion.
 */
 
 static bool
-do_regular_insertion (basic_block block, basic_block dom)
+do_pre_regular_insertion (basic_block block, basic_block dom)
 {
   bool new_stuff = false;
-  VEC (pre_expr, heap) *exprs = sorted_array_from_bitmap_set (ANTIC_IN (block));
+  vec<pre_expr> exprs;
   pre_expr expr;
+  auto_vec<pre_expr> avail;
   int i;
 
-  FOR_EACH_VEC_ELT (pre_expr, exprs, i, expr)
+  exprs = sorted_array_from_bitmap_set (ANTIC_IN (block));
+  avail.safe_grow (EDGE_COUNT (block->preds));
+
+  FOR_EACH_VEC_ELT (exprs, i, expr)
     {
-      if (expr->kind != NAME)
+      if (expr->kind == NARY
+	  || expr->kind == REFERENCE)
 	{
-	  pre_expr *avail;
 	  unsigned int val;
 	  bool by_some = false;
 	  bool cant_insert = false;
@@ -3559,11 +3173,14 @@
 	  if (bitmap_set_contains_value (AVAIL_OUT (dom), val))
 	    {
 	      if (dump_file && (dump_flags & TDF_DETAILS))
-		fprintf (dump_file, "Found fully redundant value\n");
+		{
+		  fprintf (dump_file, "Found fully redundant value: ");
+		  print_pre_expr (dump_file, expr);
+		  fprintf (dump_file, "\n");
+		}
 	      continue;
 	    }
 
-	  avail = XCNEWVEC (pre_expr, last_basic_block);
 	  FOR_EACH_EDGE (pred, ei, block->preds)
 	    {
 	      unsigned int vprime;
@@ -3572,6 +3189,7 @@
 	         and so not come across fake pred edges.  */
 	      gcc_assert (!(pred->flags & EDGE_FAKE));
 	      bprime = pred->src;
+	      /* We are looking at ANTIC_OUT of bprime.  */
 	      eprime = phi_translate (expr, ANTIC_IN (block), NULL,
 				      bprime, block);
 
@@ -3586,22 +3204,22 @@
 		 rest of the results are.  */
 	      if (eprime == NULL)
 		{
+		  avail[pred->dest_idx] = NULL;
 		  cant_insert = true;
 		  break;
 		}
 
-	      eprime = fully_constant_expression (eprime);
 	      vprime = get_expr_value_id (eprime);
 	      edoubleprime = bitmap_find_leader (AVAIL_OUT (bprime),
-						 vprime, NULL);
+						 vprime);
 	      if (edoubleprime == NULL)
 		{
-		  avail[bprime->index] = eprime;
+		  avail[pred->dest_idx] = eprime;
 		  all_same = false;
 		}
 	      else
 		{
-		  avail[bprime->index] = edoubleprime;
+		  avail[pred->dest_idx] = edoubleprime;
 		  by_some = true;
 		  /* We want to perform insertions to remove a redundancy on
 		     a path in the CFG we want to optimize for speed.  */
@@ -3609,7 +3227,7 @@
 		    do_insertion = true;
 		  if (first_s == NULL)
 		    first_s = edoubleprime;
-		  else if (!pre_expr_eq (first_s, edoubleprime))
+		  else if (!pre_expr_d::equal (first_s, edoubleprime))
 		    all_same = false;
 		}
 	    }
@@ -3630,51 +3248,54 @@
 			       "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;
+	      else if (dbg_cnt (treepre_insert))
+		{
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file, "Found partial redundancy for "
+			       "expression ");
+		      print_pre_expr (dump_file, expr);
+		      fprintf (dump_file, " (%04d)\n",
+			       get_expr_value_id (expr));
+		    }
+		  if (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
 	     an invariant, then the PHI has the same value on all
 	     edges.  Note this.  */
-	  else if (!cant_insert && all_same && eprime
-		   && (edoubleprime->kind == CONSTANT
-		       || edoubleprime->kind == NAME)
-		   && !value_id_constant_p (val))
+	  else if (!cant_insert && all_same)
 	    {
-	      unsigned int j;
-	      bitmap_iterator bi;
-	      bitmap_set_t exprset = VEC_index (bitmap_set_t,
-						value_expressions, val);
-
-	      unsigned int new_val = get_expr_value_id (edoubleprime);
-	      FOR_EACH_EXPR_ID_IN_SET (exprset, j, bi)
-		{
-		  pre_expr expr = expression_for_id (j);
-
-		  if (expr->kind == NAME)
-		    {
-		      vn_ssa_aux_t info = VN_INFO (PRE_EXPR_NAME (expr));
-		      /* Just reset the value id and valnum so it is
-			 the same as the constant we have discovered.  */
-		      if (edoubleprime->kind == CONSTANT)
-			{
-			  info->valnum = PRE_EXPR_CONSTANT (edoubleprime);
-			  pre_stats.constified++;
-			}
-		      else
-			info->valnum = VN_INFO (PRE_EXPR_NAME (edoubleprime))->valnum;
-		      info->value_id = new_val;
-		    }
-		}
+	      gcc_assert (edoubleprime->kind == CONSTANT
+			  || edoubleprime->kind == NAME);
+
+	      tree temp = make_temp_ssa_name (get_expr_type (expr),
+					      NULL, "pretmp");
+	      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);
+
+	      VN_INFO_GET (temp)->value_id = val;
+	      VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
+	      if (VN_INFO (temp)->valnum == NULL_TREE)
+		VN_INFO (temp)->valnum = temp;
+	      bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (temp));
+	      pre_expr newe = get_or_alloc_expr_for_name (temp);
+	      add_to_value (val, newe);
+	      bitmap_value_replace_in_set (AVAIL_OUT (block), newe);
+	      bitmap_insert_into_set (NEW_SETS (block), newe);
 	    }
-	  free (avail);
 	}
     }
 
-  VEC_free (pre_expr, heap, exprs);
+  exprs.release ();
   return new_stuff;
 }
 
@@ -3685,20 +3306,23 @@
    In this case, we know that putting it earlier will enable us to
    remove the later computation.  */
 
-
 static bool
-do_partial_partial_insertion (basic_block block, basic_block dom)
+do_pre_partial_partial_insertion (basic_block block, basic_block dom)
 {
   bool new_stuff = false;
-  VEC (pre_expr, heap) *exprs = sorted_array_from_bitmap_set (PA_IN (block));
+  vec<pre_expr> exprs;
   pre_expr expr;
+  auto_vec<pre_expr> avail;
   int i;
 
-  FOR_EACH_VEC_ELT (pre_expr, exprs, i, expr)
+  exprs = sorted_array_from_bitmap_set (PA_IN (block));
+  avail.safe_grow (EDGE_COUNT (block->preds));
+
+  FOR_EACH_VEC_ELT (exprs, i, expr)
     {
-      if (expr->kind != NAME)
+      if (expr->kind == NARY
+	  || expr->kind == REFERENCE)
 	{
-	  pre_expr *avail;
 	  unsigned int val;
 	  bool by_all = true;
 	  bool cant_insert = false;
@@ -3713,7 +3337,6 @@
 	  if (bitmap_set_contains_value (AVAIL_OUT (dom), val))
 	    continue;
 
-	  avail = XCNEWVEC (pre_expr, last_basic_block);
 	  FOR_EACH_EDGE (pred, ei, block->preds)
 	    {
 	      unsigned int vprime;
@@ -3738,45 +3361,220 @@
 		 rest of the results are.  */
 	      if (eprime == NULL)
 		{
+		  avail[pred->dest_idx] = NULL;
 		  cant_insert = true;
 		  break;
 		}
 
-	      eprime = fully_constant_expression (eprime);
 	      vprime = get_expr_value_id (eprime);
-	      edoubleprime = bitmap_find_leader (AVAIL_OUT (bprime),
-						 vprime, NULL);
+	      edoubleprime = bitmap_find_leader (AVAIL_OUT (bprime), vprime);
+	      avail[pred->dest_idx] = edoubleprime;
 	      if (edoubleprime == NULL)
 		{
 		  by_all = false;
 		  break;
 		}
-	      else
-		avail[bprime->index] = edoubleprime;
-
 	    }
 
 	  /* If we can insert it, it's not the same value
 	     already existing along every predecessor, and
 	     it's defined by some predecessor, it is
 	     partially redundant.  */
-	  if (!cant_insert && by_all && dbg_cnt (treepre_insert))
+	  if (!cant_insert && by_all)
 	    {
-	      pre_stats.pa_insert++;
-	      if (insert_into_preds_of_block (block, get_expression_id (expr),
-					      avail))
-		new_stuff = true;
-	    }
-	  free (avail);
+	      edge succ;
+	      bool do_insertion = false;
+
+	      /* Insert only if we can remove a later expression on a path
+		 that we want to optimize for speed.
+		 The phi node that we will be inserting in BLOCK is not free,
+		 and inserting it for the sake of !optimize_for_speed successor
+		 may cause regressions on the speed path.  */
+	      FOR_EACH_EDGE (succ, ei, block->succs)
+		{
+		  if (bitmap_set_contains_value (PA_IN (succ->dest), val)
+		      || bitmap_set_contains_value (ANTIC_IN (succ->dest), val))
+		    {
+		      if (optimize_edge_for_speed_p (succ))
+			do_insertion = true;
+		    }
+		}
+
+	      if (!do_insertion)
+		{
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file, "Skipping partial partial redundancy "
+			       "for expression ");
+		      print_pre_expr (dump_file, expr);
+		      fprintf (dump_file, " (%04d), not (partially) anticipated "
+			       "on any to be optimized for speed edges\n", val);
+		    }
+		}
+	      else if (dbg_cnt (treepre_insert))
+		{
+		  pre_stats.pa_insert++;
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file, "Found partial partial redundancy "
+			       "for expression ");
+		      print_pre_expr (dump_file, expr);
+		      fprintf (dump_file, " (%04d)\n",
+			       get_expr_value_id (expr));
+		    }
+		  if (insert_into_preds_of_block (block,
+						  get_expression_id (expr),
+						  avail))
+		    new_stuff = true;
+		}	   
+	    } 
 	}
     }
 
-  VEC_free (pre_expr, heap, exprs);
+  exprs.release ();
   return new_stuff;
 }
 
+/* Insert expressions in BLOCK to compute hoistable values up.
+   Return TRUE if something was inserted, otherwise return FALSE.
+   The caller has to make sure that BLOCK has at least two successors.  */
+
 static bool
-insert_aux (basic_block block)
+do_hoist_insertion (basic_block block)
+{
+  edge e;
+  edge_iterator ei;
+  bool new_stuff = false;
+  unsigned i;
+  gimple_stmt_iterator last;
+
+  /* At least two successors, or else...  */
+  gcc_assert (EDGE_COUNT (block->succs) >= 2);
+
+  /* Check that all successors of BLOCK are dominated by block.
+     We could use dominated_by_p() for this, but actually there is a much
+     quicker check: any successor that is dominated by BLOCK can't have
+     more than one predecessor edge.  */
+  FOR_EACH_EDGE (e, ei, block->succs)
+    if (! single_pred_p (e->dest))
+      return false;
+
+  /* Determine the insertion point.  If we cannot safely insert before
+     the last stmt if we'd have to, bail out.  */
+  last = gsi_last_bb (block);
+  if (!gsi_end_p (last)
+      && !is_ctrl_stmt (gsi_stmt (last))
+      && stmt_ends_bb_p (gsi_stmt (last)))
+    return false;
+
+  /* Compute the set of hoistable expressions from ANTIC_IN.  First compute
+     hoistable values.  */
+  bitmap_set hoistable_set;
+
+  /* A hoistable value must be in ANTIC_IN(block)
+     but not in AVAIL_OUT(BLOCK).  */
+  bitmap_initialize (&hoistable_set.values, &grand_bitmap_obstack);
+  bitmap_and_compl (&hoistable_set.values,
+		    &ANTIC_IN (block)->values, &AVAIL_OUT (block)->values);
+
+  /* Short-cut for a common case: hoistable_set is empty.  */
+  if (bitmap_empty_p (&hoistable_set.values))
+    return false;
+
+  /* Compute which of the hoistable values is in AVAIL_OUT of
+     at least one of the successors of BLOCK.  */
+  bitmap_head availout_in_some;
+  bitmap_initialize (&availout_in_some, &grand_bitmap_obstack);
+  FOR_EACH_EDGE (e, ei, block->succs)
+    /* Do not consider expressions solely because their availability
+       on loop exits.  They'd be ANTIC-IN throughout the whole loop
+       and thus effectively hoisted across loops by combination of
+       PRE and hoisting.  */
+    if (! loop_exit_edge_p (block->loop_father, e))
+      bitmap_ior_and_into (&availout_in_some, &hoistable_set.values,
+			   &AVAIL_OUT (e->dest)->values);
+  bitmap_clear (&hoistable_set.values);
+
+  /* Short-cut for a common case: availout_in_some is empty.  */
+  if (bitmap_empty_p (&availout_in_some))
+    return false;
+
+  /* Hack hoitable_set in-place so we can use sorted_array_from_bitmap_set.  */
+  hoistable_set.values = availout_in_some;
+  hoistable_set.expressions = ANTIC_IN (block)->expressions;
+
+  /* Now finally construct the topological-ordered expression set.  */
+  vec<pre_expr> exprs = sorted_array_from_bitmap_set (&hoistable_set);
+
+  bitmap_clear (&hoistable_set.values);
+
+  /* If there are candidate values for hoisting, insert expressions
+     strategically to make the hoistable expressions fully redundant.  */
+  pre_expr expr;
+  FOR_EACH_VEC_ELT (exprs, i, expr)
+    {
+      /* While we try to sort expressions topologically above the
+         sorting doesn't work out perfectly.  Catch expressions we
+	 already inserted.  */
+      unsigned int value_id = get_expr_value_id (expr);
+      if (bitmap_set_contains_value (AVAIL_OUT (block), value_id))
+	{
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      fprintf (dump_file,
+		       "Already inserted expression for ");
+	      print_pre_expr (dump_file, expr);
+	      fprintf (dump_file, " (%04d)\n", value_id);
+	    }
+	  continue;
+	}
+
+      /* OK, we should hoist this value.  Perform the transformation.  */
+      pre_stats.hoist_insert++;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file,
+		   "Inserting expression in block %d for code hoisting: ",
+		   block->index);
+	  print_pre_expr (dump_file, expr);
+	  fprintf (dump_file, " (%04d)\n", value_id);
+	}
+
+      gimple_seq stmts = NULL;
+      tree res = create_expression_by_pieces (block, expr, &stmts,
+					      get_expr_type (expr));
+
+      /* Do not return true if expression creation ultimately
+         did not insert any statements.  */
+      if (gimple_seq_empty_p (stmts))
+	res = NULL_TREE;
+      else
+	{
+	  if (gsi_end_p (last) || is_ctrl_stmt (gsi_stmt (last)))
+	    gsi_insert_seq_before (&last, stmts, GSI_SAME_STMT);
+	  else
+	    gsi_insert_seq_after (&last, stmts, GSI_NEW_STMT);
+	}
+
+      /* Make sure to not return true if expression creation ultimately
+         failed but also make sure to insert any stmts produced as they
+	 are tracked in inserted_exprs.  */
+      if (! res)
+	continue;
+
+      new_stuff = true;
+    }
+
+  exprs.release ();
+
+  return new_stuff;
+}
+
+/* Do a dominator walk on the control flow graph, and insert computations
+   of values as necessary for PRE and hoisting.  */
+
+static bool
+insert_aux (basic_block block, bool do_pre, bool do_hoist)
 {
   basic_block son;
   bool new_stuff = false;
@@ -3789,7 +3587,11 @@
 	{
 	  unsigned i;
 	  bitmap_iterator bi;
-	  bitmap_set_t newset = NEW_SETS (dom);
+	  bitmap_set_t newset;
+
+	  /* First, update the AVAIL_OUT set with anything we may have
+	     inserted higher up in the dominator tree.  */
+	  newset = NEW_SETS (dom);
 	  if (newset)
 	    {
 	      /* Note that we need to value_replace both NEW_SETS, and
@@ -3803,25 +3605,31 @@
 		  bitmap_value_replace_in_set (AVAIL_OUT (block), expr);
 		}
 	    }
-	  if (!single_pred_p (block))
+
+	  /* Insert expressions for partial redundancies.  */
+	  if (do_pre && !single_pred_p (block))
 	    {
-	      new_stuff |= do_regular_insertion (block, dom);
+	      new_stuff |= do_pre_regular_insertion (block, dom);
 	      if (do_partial_partial)
-		new_stuff |= do_partial_partial_insertion (block, dom);
+		new_stuff |= do_pre_partial_partial_insertion (block, dom);
 	    }
+
+	  /* Insert expressions for hoisting.  */
+	  if (do_hoist && EDGE_COUNT (block->succs) >= 2)
+	    new_stuff |= do_hoist_insertion (block);
 	}
     }
   for (son = first_dom_son (CDI_DOMINATORS, block);
        son;
        son = next_dom_son (CDI_DOMINATORS, son))
     {
-      new_stuff |= insert_aux (son);
+      new_stuff |= insert_aux (son, do_pre, do_hoist);
     }
 
   return new_stuff;
 }
 
-/* Perform insertion of partially redundant values.  */
+/* Perform insertion of partially redundant and hoistable values.  */
 
 static void
 insert (void)
@@ -3830,64 +3638,27 @@
   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)
     {
       num_iterations++;
-      new_stuff = insert_aux (ENTRY_BLOCK_PTR);
+      if (dump_file && dump_flags & TDF_DETAILS)
+	fprintf (dump_file, "Starting insert iteration %d\n", num_iterations);
+      new_stuff = insert_aux (ENTRY_BLOCK_PTR_FOR_FN (cfun), flag_tree_pre,
+			      flag_code_hoisting);
+
+      /* Clear the NEW sets before the next iteration.  We have already
+         fully propagated its contents.  */
+      if (new_stuff)
+	FOR_ALL_BB_FN (bb, cfun)
+	  bitmap_set_free (NEW_SETS (bb));
     }
   statistics_histogram_event (cfun, "insert iterations", num_iterations);
 }
 
 
-/* Add OP to EXP_GEN (block), and possibly to the maximal set.  */
-
-static void
-add_to_exp_gen (basic_block block, tree op)
-{
-  if (!in_fre)
-    {
-      pre_expr result;
-      if (TREE_CODE (op) == SSA_NAME && ssa_undefined_value_p (op))
-	return;
-      result = get_or_alloc_expr_for_name (op);
-      bitmap_value_insert_into_set (EXP_GEN (block), result);
-    }
-}
-
-/* Create value ids for PHI in BLOCK.  */
-
-static void
-make_values_for_phi (gimple phi, basic_block block)
-{
-  tree result = gimple_phi_result (phi);
-
-  /* We have no need for virtual phis, as they don't represent
-     actual computations.  */
-  if (is_gimple_reg (result))
-    {
-      pre_expr e = get_or_alloc_expr_for_name (result);
-      add_to_value (get_expr_value_id (e), e);
-      bitmap_insert_into_set (PHI_GEN (block), e);
-      bitmap_value_insert_into_set (AVAIL_OUT (block), e);
-      if (!in_fre)
-	{
-	  unsigned i;
-	  for (i = 0; i < gimple_phi_num_args (phi); ++i)
-	    {
-	      tree arg = gimple_phi_arg_def (phi, i);
-	      if (TREE_CODE (arg) == SSA_NAME)
-		{
-		  e = get_or_alloc_expr_for_name (arg);
-		  add_to_value (get_expr_value_id (e), e);
-		}
-	    }
-	}
-    }
-}
-
 /* Compute the AVAIL set for all basic blocks.
 
    This function performs value numbering of the statements in each basic
@@ -3906,43 +3677,51 @@
   basic_block *worklist;
   size_t sp = 0;
   unsigned i;
+  tree name;
 
   /* We pretend that default definitions are defined in the entry block.
      This includes function arguments and the static chain decl.  */
-  for (i = 1; i < num_ssa_names; ++i)
+  FOR_EACH_SSA_NAME (i, name, cfun)
     {
-      tree name = ssa_name (i);
       pre_expr e;
-      if (!name
-	  || !SSA_NAME_IS_DEFAULT_DEF (name)
+      if (!SSA_NAME_IS_DEFAULT_DEF (name)
 	  || has_zero_uses (name)
-	  || !is_gimple_reg (name))
+	  || virtual_operand_p (name))
 	continue;
 
       e = get_or_alloc_expr_for_name (name);
       add_to_value (get_expr_value_id (e), e);
-      if (!in_fre)
-	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_FOR_FN (cfun)),
+			"tmp_gen", ENTRY_BLOCK);
+      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;
+      gimple *stmt;
       basic_block dom;
-      unsigned int stmt_uid = 1;
 
       /* Pick a block from the worklist.  */
       block = worklist[--sp];
@@ -3951,30 +3730,48 @@
 	 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))
-	make_values_for_phi (gsi_stmt (gsi), block);
+      for (gphi_iterator gsi = gsi_start_phis (block); !gsi_end_p (gsi);
+	   gsi_next (&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))
+	    {
+	      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);
+	  bitmap_value_insert_into_set (AVAIL_OUT (block), e);
+	  bitmap_insert_into_set (PHI_GEN (block), e);
+	}
 
       BB_MAY_NOTRETURN (block) = 0;
 
       /* 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;
 
 	  stmt = gsi_stmt (gsi);
-	  gimple_set_uid (stmt, stmt_uid++);
 
 	  /* Cache whether the basic-block has any non-visible side-effect
 	     or control flow.
 	     If this isn't a call or it is the last stmt in the
 	     basic-block then the CFG represents things correctly.  */
-	  if (is_gimple_call (stmt)
-	      && !stmt_ends_bb_p (stmt))
+	  if (is_gimple_call (stmt) && !stmt_ends_bb_p (stmt))
 	    {
 	      /* Non-looping const functions always return normally.
 		 Otherwise the call might not return or have side-effects
@@ -3991,122 +3788,205 @@
 	      pre_expr e = get_or_alloc_expr_for_name (op);
 
 	      add_to_value (get_expr_value_id (e), e);
-	      if (!in_fre)
-		bitmap_insert_into_set (TMP_GEN (block), e);
+	      bitmap_insert_into_set (TMP_GEN (block), e);
 	      bitmap_value_insert_into_set (AVAIL_OUT (block), e);
 	    }
 
-	  if (gimple_has_volatile_ops (stmt)
-	      || stmt_could_throw_p (stmt))
+	  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))
 	    continue;
 
+	  FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
+	    {
+	      if (ssa_undefined_value_p (op))
+		continue;
+	      pre_expr e = get_or_alloc_expr_for_name (op);
+	      bitmap_value_insert_into_set (EXP_GEN (block), e);
+	    }
+
 	  switch (gimple_code (stmt))
 	    {
 	    case GIMPLE_RETURN:
-	      FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
-		add_to_exp_gen (block, op);
 	      continue;
 
 	    case GIMPLE_CALL:
 	      {
 		vn_reference_t ref;
-		unsigned int i;
-		vn_reference_op_t vro;
+		vn_reference_s ref1;
 		pre_expr result = NULL;
-		VEC(vn_reference_op_s, heap) *ops = NULL;
-
-		if (!can_value_number_call (stmt))
+
+		/* 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);
-		VEC_free (vn_reference_op_s, heap, ops);
+		vn_reference_lookup_call (as_a <gcall *> (stmt), &ref, &ref1);
 		if (!ref)
 		  continue;
 
-		for (i = 0; VEC_iterate (vn_reference_op_s,
-					 ref->operands, i,
-					 vro); i++)
+		/* If the value of the call is not invalidated in
+		   this block until it is computed, add the expression
+		   to EXP_GEN.  */
+		if (!gimple_vuse (stmt)
+		    || gimple_code
+		         (SSA_NAME_DEF_STMT (gimple_vuse (stmt))) == GIMPLE_PHI
+		    || gimple_bb (SSA_NAME_DEF_STMT
+				    (gimple_vuse (stmt))) != block)
 		  {
-		    if (vro->op0 && TREE_CODE (vro->op0) == SSA_NAME)
-		      add_to_exp_gen (block, vro->op0);
-		    if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
-		      add_to_exp_gen (block, vro->op1);
-		    if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
-		      add_to_exp_gen (block, vro->op2);
+		    result = pre_expr_pool.allocate ();
+		    result->kind = REFERENCE;
+		    result->id = 0;
+		    PRE_EXPR_REFERENCE (result) = ref;
+
+		    get_or_alloc_expression_id (result);
+		    add_to_value (get_expr_value_id (result), result);
+		    bitmap_value_insert_into_set (EXP_GEN (block), result);
 		  }
-		result = (pre_expr) pool_alloc (pre_expr_pool);
-		result->kind = REFERENCE;
-		result->id = 0;
-		PRE_EXPR_REFERENCE (result) = ref;
-
-		get_or_alloc_expression_id (result);
-		add_to_value (get_expr_value_id (result), result);
-		if (!in_fre)
-		  bitmap_value_insert_into_set (EXP_GEN (block), result);
 		continue;
 	      }
 
 	    case GIMPLE_ASSIGN:
 	      {
 		pre_expr result = NULL;
-		switch (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)))
+		switch (vn_get_stmt_kind (stmt))
 		  {
-		  case tcc_unary:
-		  case tcc_binary:
-		  case tcc_comparison:
+		  case VN_NARY:
 		    {
+		      enum tree_code code = gimple_assign_rhs_code (stmt);
 		      vn_nary_op_t nary;
-		      unsigned int i;
-
-		      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);
-
+
+		      /* COND_EXPR and VEC_COND_EXPR are awkward in
+			 that they contain an embedded complex expression.
+			 Don't even try to shove those through PRE.  */
+		      if (code == COND_EXPR
+			  || code == VEC_COND_EXPR)
+			continue;
+
+		      vn_nary_op_lookup_stmt (stmt, &nary);
 		      if (!nary)
 			continue;
 
-		      for (i = 0; i < nary->length; i++)
-			if (TREE_CODE (nary->op[i]) == SSA_NAME)
-			  add_to_exp_gen (block, nary->op[i]);
-
-		      result = (pre_expr) pool_alloc (pre_expr_pool);
+		      /* If the NARY traps and there was a preceding
+		         point in the block that might not return avoid
+			 adding the nary to EXP_GEN.  */
+		      if (BB_MAY_NOTRETURN (block)
+			  && vn_nary_may_trap (nary))
+			continue;
+
+		      result = pre_expr_pool.allocate ();
 		      result->kind = NARY;
 		      result->id = 0;
 		      PRE_EXPR_NARY (result) = nary;
 		      break;
 		    }
 
-		  case tcc_declaration:
-		  case tcc_reference:
+		  case VN_REFERENCE:
 		    {
+		      tree rhs1 = gimple_assign_rhs1 (stmt);
+		      alias_set_type set = get_alias_set (rhs1);
+		      vec<vn_reference_op_s> operands
+			= vn_reference_operands_for_lookup (rhs1);
 		      vn_reference_t ref;
-		      unsigned int i;
-		      vn_reference_op_t vro;
-
-		      vn_reference_lookup (gimple_assign_rhs1 (stmt),
-					   gimple_vuse (stmt),
-					   VN_WALK, &ref);
+		      vn_reference_lookup_pieces (gimple_vuse (stmt), set,
+						  TREE_TYPE (rhs1),
+						  operands, &ref, VN_WALK);
 		      if (!ref)
-			continue;
-
-		      for (i = 0; VEC_iterate (vn_reference_op_s,
-					       ref->operands, i,
-					       vro); i++)
+			{
+			  operands.release ();
+			  continue;
+			}
+
+		      /* If the value of the reference is not invalidated in
+			 this block until it is computed, add the expression
+			 to EXP_GEN.  */
+		      if (gimple_vuse (stmt))
 			{
-			  if (vro->op0 && TREE_CODE (vro->op0) == SSA_NAME)
-			    add_to_exp_gen (block, vro->op0);
-			  if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
-			    add_to_exp_gen (block, vro->op1);
-			  if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
-			    add_to_exp_gen (block, vro->op2);
+			  gimple *def_stmt;
+			  bool ok = true;
+			  def_stmt = SSA_NAME_DEF_STMT (gimple_vuse (stmt));
+			  while (!gimple_nop_p (def_stmt)
+				 && gimple_code (def_stmt) != GIMPLE_PHI
+				 && gimple_bb (def_stmt) == block)
+			    {
+			      if (stmt_may_clobber_ref_p
+				    (def_stmt, gimple_assign_rhs1 (stmt)))
+				{
+				  ok = false;
+				  break;
+				}
+			      def_stmt
+				= SSA_NAME_DEF_STMT (gimple_vuse (def_stmt));
+			    }
+			  if (!ok)
+			    {
+			      operands.release ();
+			      continue;
+			    }
 			}
-		      result = (pre_expr) pool_alloc (pre_expr_pool);
+
+		      /* If the load was value-numbered to another
+			 load make sure we do not use its expression
+			 for insertion if it wouldn't be a valid
+			 replacement.  */
+		      /* At the momemt we have a testcase
+			 for hoist insertion of aligned vs. misaligned
+			 variants in gcc.dg/torture/pr65270-1.c thus
+			 with just alignment to be considered we can
+			 simply replace the expression in the hashtable
+			 with the most conservative one.  */
+		      vn_reference_op_t ref1 = &ref->operands.last ();
+		      while (ref1->opcode != TARGET_MEM_REF
+			     && ref1->opcode != MEM_REF
+			     && ref1 != &ref->operands[0])
+			--ref1;
+		      vn_reference_op_t ref2 = &operands.last ();
+		      while (ref2->opcode != TARGET_MEM_REF
+			     && ref2->opcode != MEM_REF
+			     && ref2 != &operands[0])
+			--ref2;
+		      if ((ref1->opcode == TARGET_MEM_REF
+			   || ref1->opcode == MEM_REF)
+			  && (TYPE_ALIGN (ref1->type)
+			      > TYPE_ALIGN (ref2->type)))
+			ref1->type
+			  = build_aligned_type (ref1->type,
+						TYPE_ALIGN (ref2->type));
+		      /* TBAA behavior is an obvious part so make sure
+		         that the hashtable one covers this as well
+			 by adjusting the ref alias set and its base.  */
+		      if (ref->set == set
+			  || alias_set_subset_of (set, ref->set))
+			;
+		      else if (alias_set_subset_of (ref->set, set))
+			{
+			  ref->set = set;
+			  if (ref1->opcode == MEM_REF)
+			    ref1->op0
+			      = wide_int_to_tree (TREE_TYPE (ref2->op0),
+						  wi::to_wide (ref1->op0));
+			  else
+			    ref1->op2
+			      = wide_int_to_tree (TREE_TYPE (ref2->op2),
+						  wi::to_wide (ref1->op2));
+			}
+		      else
+			{
+			  ref->set = 0;
+			  if (ref1->opcode == MEM_REF)
+			    ref1->op0
+			      = wide_int_to_tree (ptr_type_node,
+						  wi::to_wide (ref1->op0));
+			  else
+			    ref1->op2
+			      = wide_int_to_tree (ptr_type_node,
+						  wi::to_wide (ref1->op2));
+			}
+		      operands.release ();
+
+		      result = pre_expr_pool.allocate ();
 		      result->kind = REFERENCE;
 		      result->id = 0;
 		      PRE_EXPR_REFERENCE (result) = ref;
@@ -4114,19 +3994,12 @@
 		    }
 
 		  default:
-		    /* For any other statement that we don't
-		       recognize, simply add all referenced
-		       SSA_NAMEs to EXP_GEN.  */
-		    FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
-		      add_to_exp_gen (block, op);
 		    continue;
 		  }
 
 		get_or_alloc_expression_id (result);
 		add_to_value (get_expr_value_id (result), result);
-		if (!in_fre)
-		  bitmap_value_insert_into_set (EXP_GEN (block), result);
-
+		bitmap_value_insert_into_set (EXP_GEN (block), result);
 		continue;
 	      }
 	    default:
@@ -4134,6 +4007,18 @@
 	    }
 	}
 
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  print_bitmap_set (dump_file, EXP_GEN (block),
+			    "exp_gen", block->index);
+	  print_bitmap_set (dump_file, PHI_GEN (block),
+			    "phi_gen", block->index);
+	  print_bitmap_set (dump_file, TMP_GEN (block),
+			    "tmp_gen", block->index);
+	  print_bitmap_set (dump_file, AVAIL_OUT (block),
+			    "avail_out", block->index);
+	}
+
       /* Put the dominator children of BLOCK on the worklist of blocks
 	 to compute available sets for.  */
       for (son = first_dom_son (CDI_DOMINATORS, block);
@@ -4145,443 +4030,9 @@
   free (worklist);
 }
 
-/* Insert the expression for SSA_VN that SCCVN thought would be simpler
-   than the available expressions for it.  The insertion point is
-   right before the first use in STMT.  Returns the SSA_NAME that should
-   be used for replacement.  */
-
-static tree
-do_SCCVN_insertion (gimple stmt, tree ssa_vn)
-{
-  basic_block bb = gimple_bb (stmt);
-  gimple_stmt_iterator gsi;
-  gimple_seq stmts = NULL;
-  tree expr;
-  pre_expr e;
-
-  /* First create a value expression from the expression we want
-     to insert and associate it with the value handle for SSA_VN.  */
-  e = get_or_alloc_expr_for (vn_get_expr_for (ssa_vn));
-  if (e == NULL)
-    return NULL_TREE;
-
-  /* Then use create_expression_by_pieces to generate a valid
-     expression to insert at this point of the IL stream.  */
-  expr = create_expression_by_pieces (bb, e, &stmts, stmt, NULL);
-  if (expr == NULL_TREE)
-    return NULL_TREE;
-  gsi = gsi_for_stmt (stmt);
-  gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
-
-  return expr;
-}
-
-/* Eliminate fully redundant computations.  */
-
-static unsigned int
-eliminate (void)
-{
-  VEC (gimple, heap) *to_remove = NULL;
-  basic_block b;
-  unsigned int todo = 0;
-  gimple_stmt_iterator gsi;
-  gimple stmt;
-  unsigned i;
-
-  FOR_EACH_BB (b)
-    {
-      for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
-	{
-	  stmt = gsi_stmt (gsi);
-
-	  /* 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 (gimple_get_lhs (stmt)) == SSA_NAME
-	      && !gimple_assign_ssa_name_copy_p (stmt)
-	      && (!gimple_assign_single_p (stmt)
-		  || !is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
-	      && !gimple_has_volatile_ops  (stmt)
-	      && !has_zero_uses (gimple_get_lhs (stmt)))
-	    {
-	      tree lhs = gimple_get_lhs (stmt);
-	      tree rhs = NULL_TREE;
-	      tree sprime = NULL;
-	      pre_expr lhsexpr = get_or_alloc_expr_for_name (lhs);
-	      pre_expr sprimeexpr;
-
-	      if (gimple_assign_single_p (stmt))
-		rhs = gimple_assign_rhs1 (stmt);
-
-	      sprimeexpr = bitmap_find_leader (AVAIL_OUT (b),
-					       get_expr_value_id (lhsexpr),
-					       NULL);
-
-	      if (sprimeexpr)
-		{
-		  if (sprimeexpr->kind == CONSTANT)
-		    sprime = PRE_EXPR_CONSTANT (sprimeexpr);
-		  else if (sprimeexpr->kind == NAME)
-		    sprime = PRE_EXPR_NAME (sprimeexpr);
-		  else
-		    gcc_unreachable ();
-		}
-
-	      /* If there is no existing leader but SCCVN knows this
-		 value is constant, use that constant.  */
-	      if (!sprime && is_gimple_min_invariant (VN_INFO (lhs)->valnum))
-		{
-		  sprime = VN_INFO (lhs)->valnum;
-		  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))
-		    {
-		      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);
-		    }
-		  pre_stats.eliminations++;
-		  propagate_tree_value_into_stmt (&gsi, sprime);
-		  stmt = gsi_stmt (gsi);
-		  update_stmt (stmt);
-		  continue;
-		}
-
-	      /* If there is no existing usable leader but SCCVN thinks
-		 it has an expression it wants to use as replacement,
-		 insert that.  */
-	      if (!sprime || sprime == lhs)
-		{
-		  tree val = VN_INFO (lhs)->valnum;
-		  if (val != VN_TOP
-		      && TREE_CODE (val) == SSA_NAME
-		      && VN_INFO (val)->needs_insertion
-		      && can_PRE_operation (vn_get_expr_for (val)))
-		    sprime = do_SCCVN_insertion (stmt, val);
-		}
-	      if (sprime
-		  && sprime != lhs
-		  && (rhs == NULL_TREE
-		      || 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))
-		    {
-		      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);
-		    }
-
-		  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++;
-		  propagate_tree_value_into_stmt (&gsi, sprime);
-		  stmt = gsi_stmt (gsi);
-		  update_stmt (stmt);
-
-		  /* 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");
-		    }
-		}
-	    }
-	  /* 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)
-		   && !is_gimple_reg (gimple_assign_lhs (stmt))
-		   && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-		       || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
-	    {
-	      tree rhs = gimple_assign_rhs1 (stmt);
-	      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);
-		    }
-
-		  /* Queue stmt for removal.  */
-		  VEC_safe_push (gimple, heap, to_remove, stmt);
-		}
-	    }
-	  /* Visit COND_EXPRs and fold the comparison with the
-	     available value-numbers.  */
-	  else if (gimple_code (stmt) == GIMPLE_COND)
-	    {
-	      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)
-		{
-		  if (integer_zerop (result))
-		    gimple_cond_make_false (stmt);
-		  else
-		    gimple_cond_make_true (stmt);
-		  update_stmt (stmt);
-		  todo = TODO_cleanup_cfg;
-		}
-	    }
-	  /* Visit indirect calls and turn them into direct calls if
-	     possible.  */
-	  if (is_gimple_call (stmt)
-	      && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
-	    {
-	      tree fn = VN_INFO (gimple_call_fn (stmt))->valnum;
-	      if (TREE_CODE (fn) == ADDR_EXPR
-		  && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
-		{
-		  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);
-		  update_stmt (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");
-		    }
-
-		  /* 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
-		     have exposed different semantics.  This may
-		     require an SSA update.  */
-		  todo |= TODO_update_ssa_only_virtuals;
-		}
-	    }
-	}
-
-      for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
-	{
-	  gimple stmt, phi = gsi_stmt (gsi);
-	  tree sprime = NULL_TREE, res = PHI_RESULT (phi);
-	  pre_expr sprimeexpr, resexpr;
-	  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
-	      || !is_gimple_reg (res))
-	    {
-	      gsi_next (&gsi);
-	      continue;
-	    }
-
-	  resexpr = get_or_alloc_expr_for_name (res);
-	  sprimeexpr = bitmap_find_leader (AVAIL_OUT (b),
-					   get_expr_value_id (resexpr), NULL);
-	  if (sprimeexpr)
-	    {
-	      if (sprimeexpr->kind == CONSTANT)
-		sprime = PRE_EXPR_CONSTANT (sprimeexpr);
-	      else if (sprimeexpr->kind == NAME)
-		sprime = PRE_EXPR_NAME (sprimeexpr);
-	      else
-		gcc_unreachable ();
-	    }
-	  if (!sprime && is_gimple_min_invariant (VN_INFO (res)->valnum))
-	    {
-	      sprime = VN_INFO (res)->valnum;
-	      if (!useless_type_conversion_p (TREE_TYPE (res),
-					      TREE_TYPE (sprime)))
-		sprime = fold_convert (TREE_TYPE (res), sprime);
-	    }
-	  if (!sprime
-	      || sprime == res)
-	    {
-	      gsi_next (&gsi);
-	      continue;
-	    }
-
-	  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");
-	    }
-
-	  remove_phi_node (&gsi, false);
-
-	  if (!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);
-	  SSA_NAME_DEF_STMT (res) = stmt;
-	  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.  */
-	  VEC_safe_push (gimple, heap, to_remove, stmt);
-	  /* If we inserted this PHI node ourself, it's not an elimination.  */
-	  if (bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
-	    pre_stats.phis--;
-	  else
-	    pre_stats.eliminations++;
-	}
-    }
-
-  /* We cannot remove stmts during BB walk, especially not release SSA
-     names there as this confuses the VN machinery.  The stmts ending
-     up in to_remove are either stores or simple copies.  */
-  FOR_EACH_VEC_ELT (gimple, to_remove, i, stmt)
-    {
-      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))
-	{
-	  SET_USE (use_p, rhs);
-	  update_stmt (use_stmt);
-	  if (bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs))
-	      && TREE_CODE (rhs) == SSA_NAME)
-	    gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true);
-	}
-
-      /* If this is a store or a now unused copy, remove it.  */
-      if (TREE_CODE (lhs) != SSA_NAME
-	  || has_zero_uses (lhs))
-	{
-	  basic_block bb = gimple_bb (stmt);
-	  gsi = gsi_for_stmt (stmt);
-	  unlink_stmt_vdef (stmt);
-	  gsi_remove (&gsi, true);
-	  if (gimple_purge_dead_eh_edges (bb))
-	    todo |= TODO_cleanup_cfg;
-	  if (TREE_CODE (lhs) == SSA_NAME)
-	    bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
-	  release_defs (stmt);
-	}
-    }
-  VEC_free (gimple, heap, to_remove);
-
-  return todo;
-}
-
-/* Borrow a bit of tree-ssa-dce.c for the moment.
-   XXX: In 4.1, we should be able to just run a DCE pass after PRE, though
-   this may be a bit faster, and we may want critical edges kept split.  */
-
-/* If OP's defining statement has not already been determined to be necessary,
-   mark that statement necessary. Return the stmt, if it is newly
-   necessary.  */
-
-static inline gimple
-mark_operand_necessary (tree op)
-{
-  gimple stmt;
-
-  gcc_assert (op);
-
-  if (TREE_CODE (op) != SSA_NAME)
-    return NULL;
-
-  stmt = SSA_NAME_DEF_STMT (op);
-  gcc_assert (stmt);
-
-  if (gimple_plf (stmt, NECESSARY)
-      || gimple_nop_p (stmt))
-    return NULL;
-
-  gimple_set_plf (stmt, NECESSARY, true);
-  return stmt;
-}
-
-/* Because we don't follow exactly the standard PRE algorithm, and decide not
+/* Cheap DCE of a known set of possibly dead stmts.
+
+   Because we don't follow exactly the standard PRE algorithm, and decide not
    to insert PHI nodes sometimes, and because value numbering of casts isn't
    perfect, we sometimes end up inserting dead code.   This simple DCE-like
    pass removes any insertions we made that weren't actually used.  */
@@ -4589,309 +4040,166 @@
 static void
 remove_dead_inserted_code (void)
 {
-  bitmap worklist;
-  unsigned i;
-  bitmap_iterator bi;
-  gimple t;
-
-  worklist = BITMAP_ALLOC (NULL);
-  EXECUTE_IF_SET_IN_BITMAP (inserted_exprs, 0, i, bi)
+  /* ???  Re-use inserted_exprs as worklist not only as initial set.
+     This may end up removing non-inserted code as well.  If we
+     keep inserted_exprs unchanged we could restrict new worklist
+     elements to members of inserted_exprs.  */
+  bitmap worklist = inserted_exprs;
+  while (! bitmap_empty_p (worklist))
     {
-      t = SSA_NAME_DEF_STMT (ssa_name (i));
-      if (gimple_plf (t, NECESSARY))
-	bitmap_set_bit (worklist, i);
-    }
-  while (!bitmap_empty_p (worklist))
-    {
-      i = bitmap_first_set_bit (worklist);
+      /* Pop item.  */
+      unsigned i = bitmap_first_set_bit (worklist);
       bitmap_clear_bit (worklist, i);
-      t = SSA_NAME_DEF_STMT (ssa_name (i));
-
-      /* PHI nodes are somewhat special in that each PHI alternative has
-	 data and control dependencies.  All the statements feeding the
-	 PHI node's arguments are always necessary. */
-      if (gimple_code (t) == GIMPLE_PHI)
+
+      tree def = ssa_name (i);
+      /* Removed by somebody else or still in use.  */
+      if (! def || ! has_zero_uses (def))
+	continue;
+
+      gimple *t = SSA_NAME_DEF_STMT (def);
+      if (gimple_has_side_effects (t))
+	continue;
+
+      /* Add uses to the worklist.  */
+      ssa_op_iter iter;
+      use_operand_p use_p;
+      FOR_EACH_PHI_OR_STMT_USE (use_p, t, iter, SSA_OP_USE)
 	{
-	  unsigned k;
-
-	  for (k = 0; k < gimple_phi_num_args (t); k++)
-	    {
-	      tree arg = PHI_ARG_DEF (t, k);
-	      if (TREE_CODE (arg) == SSA_NAME)
-		{
-		  gimple n = mark_operand_necessary (arg);
-		  if (n)
-		    bitmap_set_bit (worklist, SSA_NAME_VERSION (arg));
-		}
-	    }
+	  tree use = USE_FROM_PTR (use_p);
+	  if (TREE_CODE (use) == SSA_NAME
+	      && ! SSA_NAME_IS_DEFAULT_DEF (use))
+	    bitmap_set_bit (worklist, SSA_NAME_VERSION (use));
 	}
+
+      /* Remove stmt.  */
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, "Removing unnecessary insertion:");
+	  print_gimple_stmt (dump_file, t, 0);
+	}
+      gimple_stmt_iterator gsi = gsi_for_stmt (t);
+      if (gimple_code (t) == GIMPLE_PHI)
+	remove_phi_node (&gsi, true);
       else
 	{
-	  /* Propagate through the operands.  Examine all the USE, VUSE and
-	     VDEF operands in this statement.  Mark all the statements
-	     which feed this statement's uses as necessary.  */
-	  ssa_op_iter iter;
-	  tree use;
-
-	  /* The operands of VDEF expressions are also needed as they
-	     represent potential definitions that may reach this
-	     statement (VDEF operands allow us to follow def-def
-	     links).  */
-
-	  FOR_EACH_SSA_TREE_OPERAND (use, t, iter, SSA_OP_ALL_USES)
-	    {
-	      gimple n = mark_operand_necessary (use);
-	      if (n)
-		bitmap_set_bit (worklist, SSA_NAME_VERSION (use));
-	    }
+	  gsi_remove (&gsi, true);
+	  release_defs (t);
 	}
     }
-
-  EXECUTE_IF_SET_IN_BITMAP (inserted_exprs, 0, i, bi)
-    {
-      t = SSA_NAME_DEF_STMT (ssa_name (i));
-      if (!gimple_plf (t, NECESSARY))
-	{
-	  gimple_stmt_iterator gsi;
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Removing unnecessary insertion:");
-	      print_gimple_stmt (dump_file, t, 0, 0);
-	    }
-
-	  gsi = gsi_for_stmt (t);
-	  if (gimple_code (t) == GIMPLE_PHI)
-	    remove_phi_node (&gsi, true);
-	  else
-	    {
-	      gsi_remove (&gsi, true);
-	      release_defs (t);
-	    }
-	}
-    }
-  BITMAP_FREE (worklist);
-}
-
-/* Compute a reverse post-order in *POST_ORDER.  If INCLUDE_ENTRY_EXIT is
-   true, then then ENTRY_BLOCK and EXIT_BLOCK are included.  Returns
-   the number of visited blocks.  */
-
-static int
-my_rev_post_order_compute (int *post_order, bool include_entry_exit)
-{
-  edge_iterator *stack;
-  int sp;
-  int post_order_num = 0;
-  sbitmap visited;
-
-  if (include_entry_exit)
-    post_order[post_order_num++] = EXIT_BLOCK;
-
-  /* Allocate stack for back-tracking up CFG.  */
-  stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
-  sp = 0;
-
-  /* Allocate bitmap to track nodes that have been visited.  */
-  visited = sbitmap_alloc (last_basic_block);
-
-  /* None of the nodes in the CFG have been visited yet.  */
-  sbitmap_zero (visited);
-
-  /* Push the last edge on to the stack.  */
-  stack[sp++] = ei_start (EXIT_BLOCK_PTR->preds);
-
-  while (sp)
-    {
-      edge_iterator ei;
-      basic_block src;
-      basic_block dest;
-
-      /* Look at the edge on the top of the stack.  */
-      ei = stack[sp - 1];
-      src = ei_edge (ei)->src;
-      dest = ei_edge (ei)->dest;
-
-      /* Check if the edge destination has been visited yet.  */
-      if (src != ENTRY_BLOCK_PTR && ! TEST_BIT (visited, src->index))
-        {
-          /* Mark that we have visited the destination.  */
-          SET_BIT (visited, src->index);
-
-          if (EDGE_COUNT (src->preds) > 0)
-            /* Since the DEST node has been visited for the first
-               time, check its successors.  */
-            stack[sp++] = ei_start (src->preds);
-          else
-            post_order[post_order_num++] = src->index;
-        }
-      else
-        {
-          if (ei_one_before_end_p (ei) && dest != EXIT_BLOCK_PTR)
-            post_order[post_order_num++] = dest->index;
-
-          if (!ei_one_before_end_p (ei))
-            ei_next (&stack[sp - 1]);
-          else
-            sp--;
-        }
-    }
-
-  if (include_entry_exit)
-    post_order[post_order_num++] = ENTRY_BLOCK;
-
-  free (stack);
-  sbitmap_free (visited);
-  return post_order_num;
 }
 
 
 /* Initialize data structures used by PRE.  */
 
 static void
-init_pre (bool do_fre)
+init_pre (void)
 {
   basic_block bb;
 
   next_expression_id = 1;
-  expressions = NULL;
-  VEC_safe_push (pre_expr, heap, expressions, NULL);
-  value_expressions = VEC_alloc (bitmap_set_t, heap, get_max_value_id () + 1);
-  VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
-			 get_max_value_id() + 1);
-  name_to_id = NULL;
-
-  in_fre = do_fre;
+  expressions.create (0);
+  expressions.safe_push (NULL);
+  value_expressions.create (get_max_value_id () + 1);
+  value_expressions.safe_grow_cleared (get_max_value_id () + 1);
+  name_to_id.create (0);
 
   inserted_exprs = BITMAP_ALLOC (NULL);
-  need_creation = NULL;
-  pretemp = NULL_TREE;
-  storetemp = NULL_TREE;
-  prephitemp = NULL_TREE;
 
   connect_infinite_loops_to_exit ();
   memset (&pre_stats, 0, sizeof (pre_stats));
 
-
-  postorder = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS);
-  my_rev_post_order_compute (postorder, false);
-
   alloc_aux_for_blocks (sizeof (struct bb_bitmap_sets));
 
-  calculate_dominance_info (CDI_POST_DOMINATORS);
   calculate_dominance_info (CDI_DOMINATORS);
 
   bitmap_obstack_initialize (&grand_bitmap_obstack);
-  phi_translate_table = htab_create (5110, expr_pred_trans_hash,
-				     expr_pred_trans_eq, free);
-  expression_to_id = htab_create (num_ssa_names * 3,
-				  pre_expr_hash,
-				  pre_expr_eq, NULL);
-  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 ();
       TMP_GEN (bb) = bitmap_set_new ();
       AVAIL_OUT (bb) = bitmap_set_new ();
     }
-
-  need_eh_cleanup = BITMAP_ALLOC (NULL);
-  need_ab_cleanup = BITMAP_ALLOC (NULL);
 }
 
 
 /* Deallocate data structures used by PRE.  */
 
 static void
-fini_pre (bool do_fre)
+fini_pre ()
 {
-  free (postorder);
-  VEC_free (bitmap_set_t, heap, value_expressions);
+  value_expressions.release ();
   BITMAP_FREE (inserted_exprs);
-  VEC_free (gimple, heap, need_creation);
   bitmap_obstack_release (&grand_bitmap_obstack);
-  free_alloc_pool (bitmap_set_pool);
-  free_alloc_pool (pre_expr_pool);
-  htab_delete (phi_translate_table);
-  htab_delete (expression_to_id);
-  VEC_free (unsigned, heap, name_to_id);
+  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 ();
-
-  free_dominance_info (CDI_POST_DOMINATORS);
-
-  if (!bitmap_empty_p (need_eh_cleanup))
-    {
-      gimple_purge_all_dead_eh_edges (need_eh_cleanup);
-      cleanup_tree_cfg ();
-    }
-
-  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 ();
 }
 
-/* Main entry point to the SSA-PRE pass.  DO_FRE is true if the caller
-   only wants to do full redundancy elimination.  */
-
-static unsigned int
-execute_pre (bool do_fre)
+namespace {
+
+const pass_data pass_data_pre =
+{
+  GIMPLE_PASS, /* type */
+  "pre", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_PRE, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* 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 || flag_code_hoisting != 0; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_pre
+
+unsigned int
+pass_pre::execute (function *fun)
 {
   unsigned int todo = 0;
 
-  do_partial_partial = optimize > 2 && optimize_function_for_speed_p (cfun);
+  do_partial_partial =
+    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.  */
-  if (!do_fre)
-    loop_optimizer_init (LOOPS_NORMAL);
-
-  if (!run_scc_vn (do_fre ? VN_WALKREWRITE : VN_WALK))
-    {
-      if (!do_fre)
-	loop_optimizer_finalize ();
-
-      return 0;
-    }
-
-  init_pre (do_fre);
+  loop_optimizer_init (LOOPS_NORMAL);
+  split_critical_edges ();
+
+  run_scc_vn (VN_WALK);
+
+  init_pre ();
   scev_initialize ();
 
   /* Collect and value number expressions computed in each basic block.  */
   compute_avail ();
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      basic_block bb;
-
-      FOR_ALL_BB (bb)
-	{
-	  print_bitmap_set (dump_file, EXP_GEN (bb), "exp_gen", bb->index);
-	  print_bitmap_set (dump_file, PHI_GEN (bb), "phi_gen", bb->index);
-	  print_bitmap_set (dump_file, TMP_GEN (bb), "tmp_gen", bb->index);
-	  print_bitmap_set (dump_file, AVAIL_OUT (bb), "avail_out", bb->index);
-	}
-    }
-
   /* Insert can get quite slow on an incredibly large number of basic
      blocks due to some quadratic behavior.  Until this behavior is
      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 (!do_fre && n_basic_blocks < 4000)
+  if (n_basic_blocks_for_fn (fun) < 4000)
     {
       compute_antic ();
       insert ();
@@ -4903,94 +4211,53 @@
   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 ();
-
-  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 (cfun, "Constified", pre_stats.constified);
+  todo |= vn_eliminate (inserted_exprs);
+
+  statistics_counter_event (fun, "Insertions", pre_stats.insertions);
+  statistics_counter_event (fun, "PA inserted", pre_stats.pa_insert);
+  statistics_counter_event (fun, "HOIST inserted", pre_stats.hoist_insert);
+  statistics_counter_event (fun, "New PHIs", pre_stats.phis);
 
   clear_expression_ids ();
-  free_scc_vn ();
-  if (!do_fre)
-    {
-      remove_dead_inserted_code ();
-      todo |= TODO_verify_flow;
-    }
 
   scev_finalize ();
-  fini_pre (do_fre);
+  remove_dead_inserted_code ();
+  fini_pre ();
+  loop_optimizer_finalize ();
+
+  /* Restore SSA info before tail-merging as that resets it as well.  */
+  scc_vn_restore_ssa_info ();
+
+  /* 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 ();
+
+  /* Tail merging invalidates the virtual SSA web, together with
+     cfg-cleanup opportunities exposed by PRE this will wreck the
+     SSA updating machinery.  So make sure to run update-ssa
+     manually, before eventually scheduling cfg-cleanup as part of
+     the todo.  */
+  update_ssa (TODO_update_ssa_only_virtuals);
 
   return todo;
 }
 
-/* Gate and execute functions for PRE.  */
-
-static unsigned int
-do_pre (void)
-{
-  return execute_pre (false);
-}
-
-static bool
-gate_pre (void)
-{
-  return flag_tree_pre != 0;
-}
-
-struct gimple_opt_pass pass_pre =
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_pre (gcc::context *ctxt)
 {
- {
-  GIMPLE_PASS,
-  "pre",				/* name */
-  gate_pre,				/* gate */
-  do_pre,				/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  TV_TREE_PRE,				/* tv_id */
-  PROP_no_crit_edges | PROP_cfg
-    | PROP_ssa,				/* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  TODO_rebuild_alias,			/* todo_flags_start */
-  TODO_update_ssa_only_virtuals | TODO_dump_func | TODO_ggc_collect
-  | TODO_verify_ssa /* todo_flags_finish */
- }
-};
-
-
-/* Gate and execute functions for FRE.  */
-
-static unsigned int
-execute_fre (void)
-{
-  return execute_pre (true);
+  return new pass_pre (ctxt);
 }
-
-static bool
-gate_fre (void)
-{
-  return flag_tree_fre != 0;
-}
-
-struct gimple_opt_pass pass_fre =
-{
- {
-  GIMPLE_PASS,
-  "fre",				/* name */
-  gate_fre,				/* gate */
-  execute_fre,				/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  TV_TREE_FRE,				/* tv_id */
-  PROP_cfg | PROP_ssa,			/* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
- }
-};