c-ada-spec.c (dump_ada_double_name): New case.
[gcc.git] / gcc / tree-ssa-pre.c
index c45eb2e9095a91d957614dc99c57111af9f703bf..55295e171e9e48d3538205b066f7c0e9309ac77e 100644 (file)
@@ -1,5 +1,5 @@
 /* Full and partial redundancy elimination and code hoisting on SSA GIMPLE.
-   Copyright (C) 2001-2016 Free Software Foundation, Inc.
+   Copyright (C) 2001-2018 Free Software Foundation, Inc.
    Contributed by Daniel Berlin <dan@dberlin.org> and Steven Bosscher
    <stevenb@suse.de>
 
@@ -39,7 +39,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
-#include "tree-ssa-loop.h"
 #include "tree-into-ssa.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
@@ -50,9 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "domwalk.h"
 #include "tree-ssa-propagate.h"
-#include "ipa-utils.h"
+#include "tree-ssa-dce.h"
 #include "tree-cfgcleanup.h"
-#include "langhooks.h"
 #include "alias.h"
 
 /* Even though this file is called tree-ssa-pre.c, we actually
@@ -403,15 +401,6 @@ expression_for_id (unsigned int id)
   return expressions[id];
 }
 
-/* Free the expression id field in all of our expressions,
-   and then destroy the expressions array.  */
-
-static void
-clear_expression_ids (void)
-{
-  expressions.release ();
-}
-
 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.  */
@@ -516,9 +505,6 @@ typedef struct bb_bitmap_sets
    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;
 
@@ -537,11 +523,8 @@ 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 void bitmap_set_and (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 *,
                                         tree);
@@ -554,12 +537,6 @@ static unsigned int get_expr_value_id (pre_expr);
 static object_allocator<bitmap_set> bitmap_set_pool ("Bitmap sets");
 static bitmap_obstack grand_bitmap_obstack;
 
-/* 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;
-
 /* A three tuple {e, pred, v} used to cache phi translations in the
    phi_translate_table.  */
 
@@ -722,37 +699,29 @@ sccvn_valnum_from_value_id (unsigned int val)
 /* 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));
-    }
+  bitmap_clear_bit (&set->values, val);
+  bitmap_clear_bit (&set->expressions, get_expression_id (expr));
 }
 
+/* Insert an expression EXPR into a bitmapped set.  */
+
 static void
-bitmap_insert_into_set_1 (bitmap_set_t set, pre_expr expr,
-                         unsigned int val, bool allow_constants)
+bitmap_insert_into_set (bitmap_set_t set, pre_expr expr)
 {
-  if (allow_constants || !value_id_constant_p (val))
+  unsigned int val = get_expr_value_id (expr);
+  if (! value_id_constant_p (val))
     {
-      /* We specifically expect this and only this function to be able to
-        insert constants into a set.  */
+      /* 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));
     }
 }
 
-/* Insert an expression EXPR into a bitmapped set.  */
-
-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);
-}
-
 /* Copy a bitmapped set ORIG, into bitmapped set DEST.  */
 
 static void
@@ -807,36 +776,10 @@ sorted_array_from_bitmap_set (bitmap_set_t set)
   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;
@@ -855,25 +798,27 @@ bitmap_set_subtract (bitmap_set_t dest, bitmap_set_t orig)
   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);
 }
 
 
@@ -885,9 +830,6 @@ bitmap_set_contains_value (bitmap_set_t set, unsigned int value_id)
   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);
 }
 
@@ -897,44 +839,6 @@ bitmap_set_contains_expr (bitmap_set_t set, const pre_expr expr)
   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 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 = value_expressions[lookfor];
-  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 ();
-}
-
 /* Return true if two bitmap sets are equal.  */
 
 static bool
@@ -950,9 +854,33 @@ static void
 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);
 }
@@ -981,13 +909,18 @@ bitmap_value_insert_into_set (bitmap_set_t set, pre_expr expr)
 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:
       {
@@ -996,7 +929,7 @@ print_pre_expr (FILE *outfile, const pre_expr expr)
        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, ",");
          }
@@ -1027,16 +960,16 @@ print_pre_expr (FILE *outfile, const pre_expr expr)
              }
            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)
@@ -1048,7 +981,7 @@ print_pre_expr (FILE *outfile, const pre_expr expr)
        if (ref->vuse)
          {
            fprintf (outfile, "@");
-           print_generic_expr (outfile, ref->vuse, 0);
+           print_generic_expr (outfile, ref->vuse);
          }
       }
       break;
@@ -1173,35 +1106,11 @@ get_or_alloc_expr_for (tree t)
     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.allocate ();
-         e->kind = NARY;
-         PRE_EXPR_NARY (e) = result;
-         result_id = lookup_expression_id (e);
-         if (result_id != 0)
-           {
-             pre_expr_pool.remove (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)
@@ -1218,10 +1127,8 @@ fully_constant_expression (pre_expr e)
          return e;
        if (is_gimple_min_invariant (res))
          return get_or_alloc_expr_for_constant (res);
-       /* 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.  */
+       if (TREE_CODE (res) == SSA_NAME)
+         return get_or_alloc_expr_for_name (res);
        return e;
       }
     case REFERENCE:
@@ -1315,17 +1222,20 @@ translate_vuse_through_block (vec<vn_reference_op_s> operands,
 }
 
 /* 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);
   if (!result && set2)
     result = bitmap_find_leader (set2, val);
+  if (!result && set3)
+    result = bitmap_find_leader (set3, val);
   return result;
 }
 
@@ -1348,7 +1258,7 @@ get_expr_type (const pre_expr e)
   gcc_unreachable ();
 }
 
-/* Get a representative SSA_NAME for a given expression.
+/* Get a representative SSA_NAME for a given expression that is available in B.
    Since all of our sub-expressions are treated as values, we require
    them to be SSA_NAME's for simplicity.
    Prior versions of GVNPRE used to use "value handles" here, so that
@@ -1357,9 +1267,9 @@ get_expr_type (const pre_expr e)
    them to be usable without finding leaders).  */
 
 static tree
-get_representative_for (const pre_expr e)
+get_representative_for (const pre_expr e, basic_block b = NULL)
 {
-  tree name;
+  tree name, valnum = NULL_TREE;
   unsigned int value_id = get_expr_value_id (e);
 
   switch (e->kind)
@@ -1380,7 +1290,18 @@ get_representative_for (const pre_expr e)
          {
            pre_expr rep = expression_for_id (i);
            if (rep->kind == NAME)
-             return VN_INFO (PRE_EXPR_NAME (rep))->valnum;
+             {
+               tree name = PRE_EXPR_NAME (rep);
+               valnum = VN_INFO (name)->valnum;
+               gimple *def = SSA_NAME_DEF_STMT (name);
+               /* We have to return either a new representative or one
+                  that can be used for expression simplification and thus
+                  is available in B.  */
+               if (! b 
+                   || gimple_nop_p (def)
+                   || dominated_by_p (CDI_DOMINATORS, b, gimple_bb (def)))
+                 return name;
+             }
            else if (rep->kind == CONSTANT)
              return PRE_EXPR_CONSTANT (rep);
          }
@@ -1396,14 +1317,14 @@ get_representative_for (const pre_expr e)
      to compute it.  */
   name = make_temp_ssa_name (get_expr_type (e), gimple_build_nop (), "pretmp");
   VN_INFO_GET (name)->value_id = value_id;
-  VN_INFO (name)->valnum = name;
+  VN_INFO (name)->valnum = valnum ? 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 && (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, " (%04d)\n", value_id);
@@ -1413,7 +1334,6 @@ get_representative_for (const pre_expr e)
 }
 
 
-
 static pre_expr
 phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
               basic_block pred, basic_block phiblock);
@@ -1448,7 +1368,9 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                leader = find_leader_in_sets (op_val_id, set1, set2);
                 result = phi_translate (leader, set1, set2, pred, phiblock);
                if (result && result != leader)
-                 newnary->op[i] = get_representative_for (result);
+                 /* Force a leader as well as we are simplifying this
+                    expression.  */
+                 newnary->op[i] = get_representative_for (result, pred);
                else if (!result)
                  return NULL;
 
@@ -1464,8 +1386,36 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            constant = fully_constant_expression (expr);
            PRE_EXPR_NARY (expr) = nary;
            if (constant != expr)
-             return constant;
+             {
+               /* 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;
+             }
 
+           /* vn_nary_* do not valueize operands.  */
+           for (i = 0; i < newnary->length; ++i)
+             if (TREE_CODE (newnary->op[i]) == SSA_NAME)
+               newnary->op[i] = VN_INFO (newnary->op[i])->valnum;
            tree result = vn_nary_op_lookup_pieces (newnary->length,
                                                    newnary->opcode,
                                                    newnary->type,
@@ -1585,7 +1535,6 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
        if (changed || newvuse != vuse)
          {
            unsigned int new_val_id;
-           pre_expr constant;
 
            tree result = vn_reference_lookup_pieces (newvuse, ref->set,
                                                      ref->type,
@@ -1630,15 +1579,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            expr->id = 0;
 
            if (newref)
-             {
-               PRE_EXPR_REFERENCE (expr) = newref;
-               constant = fully_constant_expression (expr);
-               if (constant != expr)
-                 return constant;
-
-               new_val_id = newref->value_id;
-               get_or_alloc_expression_id (expr);
-             }
+             new_val_id = newref->value_id;
            else
              {
                if (changed || !same_valid)
@@ -1656,12 +1597,9 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                                                     newoperands,
                                                     result, new_val_id);
                newoperands = vNULL;
-               PRE_EXPR_REFERENCE (expr) = newref;
-               constant = fully_constant_expression (expr);
-               if (constant != expr)
-                 return constant;
-               get_or_alloc_expression_id (expr);
              }
+           PRE_EXPR_REFERENCE (expr) = newref;
+           get_or_alloc_expression_id (expr);
            add_to_value (new_val_id, expr);
          }
        newoperands.release ();
@@ -1966,14 +1904,12 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr)
     }
 }
 
-/* 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)
+clean (bitmap_set_t set1, bitmap_set_t set2 = NULL)
 {
   vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1);
   pre_expr expr;
@@ -1982,26 +1918,7 @@ dependent_clean (bitmap_set_t set1, bitmap_set_t set2)
   FOR_EACH_VEC_ELT (exprs, i, expr)
     {
       if (!valid_in_sets (set1, set2, expr))
-       bitmap_remove_from_set (set1, expr);
-    }
-  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.  */
-
-static void
-clean (bitmap_set_t set)
-{
-  vec<pre_expr> exprs = sorted_array_from_bitmap_set (set);
-  pre_expr expr;
-  int i;
-
-  FOR_EACH_VEC_ELT (exprs, i, expr)
-    {
-      if (!valid_in_sets (set, NULL, expr))
-       bitmap_remove_from_set (set, expr);
+       bitmap_remove_expr_from_set (set1, expr);
     }
   exprs.release ();
 }
@@ -2014,9 +1931,17 @@ prune_clobbered_mems (bitmap_set_t set, basic_block block)
 {
   bitmap_iterator bi;
   unsigned i;
+  pre_expr to_remove = NULL;
 
   FOR_EACH_EXPR_ID_IN_SET (set, i, bi)
     {
+      /* 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)
        {
@@ -2030,7 +1955,7 @@ prune_clobbered_mems (bitmap_set_t set, basic_block block)
                                           block, gimple_bb (def_stmt)))
                      || (gimple_bb (def_stmt) == block
                          && value_dies_in_block_x (expr, block))))
-               bitmap_remove_from_set (set, expr);
+               to_remove = expr;
            }
        }
       else if (expr->kind == NARY)
@@ -2042,9 +1967,13 @@ prune_clobbered_mems (bitmap_set_t set, basic_block block)
             as the available expression might be after the exit point.  */
          if (BB_MAY_NOTRETURN (block)
              && vn_nary_may_trap (nary))
-           bitmap_remove_from_set (set, expr);
+           to_remove = expr;
        }
     }
+
+  /* Remove queued expr.  */
+  if (to_remove)
+    bitmap_remove_expr_from_set (set, to_remove);
 }
 
 static sbitmap has_abnormal_preds;
@@ -2057,21 +1986,21 @@ static sbitmap has_abnormal_preds;
      ANTIC_OUT[BLOCK] = phi_translate (ANTIC_IN[succ(BLOCK)])
 
    ANTIC_IN[BLOCK] = clean(ANTIC_OUT[BLOCK] U EXP_GEN[BLOCK] - TMP_GEN[BLOCK])
-*/
+
+   Note that clean() is deferred until after the iteration.  */
 
 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 was_visited = BB_VISITED (block);
 
-  old = ANTIC_OUT = S = NULL;
+  bool changed = ! BB_VISITED (block);
   BB_VISITED (block) = 1;
+  old = ANTIC_OUT = S = NULL;
 
   /* If any edges from predecessors are abnormal, antic_in is empty,
      so do nothing.  */
@@ -2126,17 +2055,54 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
 
       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);
+           }
+       }
+      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);
        }
     }
 
@@ -2145,11 +2111,11 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
   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 */
@@ -2157,9 +2123,10 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
     bitmap_value_insert_into_set (ANTIC_IN (block),
                                  expression_for_id (bii));
 
-  clean (ANTIC_IN (block));
+  /* clean (ANTIC_IN (block)) is defered to after the iteration converged
+     because it can cause non-convergence, see for example PR81181.  */
 
-  if (!was_visited || !bitmap_set_equal (old, ANTIC_IN (block)))
+  if (!bitmap_set_equal (old, ANTIC_IN (block)))
     changed = true;
 
  maybe_dump_sets:
@@ -2193,8 +2160,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
    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 void
@@ -2287,7 +2253,7 @@ compute_partial_antic_aux (basic_block 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.  */
@@ -2297,7 +2263,7 @@ compute_partial_antic_aux (basic_block block,
   /* PA_IN[block] = PA_IN[block] - ANTIC_IN[block] */
   bitmap_set_subtract_values (PA_IN (block), ANTIC_IN (block));
 
-  dependent_clean (PA_IN (block), ANTIC_IN (block));
+  clean (PA_IN (block), ANTIC_IN (block));
 
  maybe_dump_sets:
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2338,9 +2304,6 @@ compute_antic (void)
        if (e->flags & EDGE_ABNORMAL)
          {
            bitmap_set_bit (has_abnormal_preds, block->index);
-
-           /* We also anticipate nothing.  */
-           BB_VISITED (block) = 1;
            break;
          }
 
@@ -2356,11 +2319,13 @@ compute_antic (void)
   /* 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.  */
-  int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
-  int postorder_num = inverted_post_order_compute (postorder);
+  auto_vec<int, 20> postorder;
+  inverted_post_order_compute (&postorder);
 
-  sbitmap worklist = sbitmap_alloc (last_basic_block_for_fn (cfun) + 1);
-  bitmap_ones (worklist);
+  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))
@@ -2371,7 +2336,7 @@ compute_antic (void)
         for PA ANTIC computation.  */
       num_iterations++;
       changed = false;
-      for (i = postorder_num - 1; i >= 0; i--)
+      for (i = postorder.length () - 1; i >= 0; i--)
        {
          if (bitmap_bit_p (worklist, postorder[i]))
            {
@@ -2391,6 +2356,12 @@ compute_antic (void)
       gcc_checking_assert (num_iterations < 500);
     }
 
+  /* We have to clean after the dataflow problem converged as cleaning
+     can cause non-convergence because it is based on expressions
+     rather than values.  */
+  FOR_EACH_BB_FN (block, cfun)
+    clean (ANTIC_IN (block));
+
   statistics_histogram_event (cfun, "compute_antic iterations",
                              num_iterations);
 
@@ -2398,7 +2369,8 @@ compute_antic (void)
     {
       /* For partial antic we ignore backedges and thus we do not need
          to perform any iteration when we process blocks in postorder.  */
-      postorder_num = pre_and_rev_post_order_compute (NULL, postorder, false);
+      int postorder_num
+       = pre_and_rev_post_order_compute (NULL, postorder.address (), false);
       for (i = postorder_num - 1 ; i >= 0; i--)
        {
          basic_block block = BASIC_BLOCK_FOR_FN (cfun, postorder[i]);
@@ -2409,8 +2381,6 @@ compute_antic (void)
     }
 
   sbitmap_free (has_abnormal_preds);
-  sbitmap_free (worklist);
-  free (postorder);
 }
 
 
@@ -2443,7 +2413,7 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
        if (TREE_CODE (baseop) == ADDR_EXPR
            && handled_component_p (TREE_OPERAND (baseop, 0)))
          {
-           HOST_WIDE_INT off;
+           poly_int64 off;
            tree base;
            base = get_addr_base_and_unit_offset (TREE_OPERAND (baseop, 0),
                                                  &off);
@@ -2570,12 +2540,14 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
               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)));
                genop3 = find_or_generate_expression (block, genop3, stmts);
                if (!genop3)
                  return NULL_TREE;
@@ -2690,8 +2662,6 @@ find_or_generate_expression (basic_block block, tree op, gimple_seq *stmts)
   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,
@@ -2727,6 +2697,8 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
        that value numbering saw through.  */
     case NAME:
       folded = PRE_EXPR_NAME (expr);
+      if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (folded))
+       return NULL_TREE;
       if (useless_type_conversion_p (exprtype, TREE_TYPE (folded)))
        return folded;
       break;
@@ -2867,7 +2839,24 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
       gimple_seq_discard (forced_stmts);
       return folded;
     }
-
+  /* 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
@@ -2892,7 +2881,6 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
            }
 
          bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (forcedname));
-         gimple_set_plf (stmt, NECESSARY, false);
        }
       gimple_seq_add_seq (stmts, forced_stmts);
     }
@@ -2925,7 +2913,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Inserted ");
-      print_gimple_stmt (dump_file, gsi_stmt (gsi_last (*stmts)), 0, 0);
+      print_gimple_stmt (dump_file, gsi_stmt (gsi_last (*stmts)), 0);
       fprintf (dump_file, " in predecessor %d (%04d)\n",
               block->index, value_id);
     }
@@ -2987,7 +2975,8 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
       gcc_assert (!(pred->flags & EDGE_ABNORMAL));
       if (!gimple_seq_empty_p (stmts))
        {
-         gsi_insert_seq_on_edge (pred, stmts);
+         basic_block new_bb = gsi_insert_seq_on_edge_immediate (pred, stmts);
+         gcc_assert (! new_bb);
          insertions = true;
        }
       if (!builtexpr)
@@ -3015,7 +3004,6 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
   temp = make_temp_ssa_name (type, NULL, "prephitmp");
   phi = create_phi_node (temp, block);
 
-  gimple_set_plf (phi, NECESSARY, false);
   VN_INFO_GET (temp)->value_id = val;
   VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
   if (VN_INFO (temp)->valnum == NULL_TREE)
@@ -3086,7 +3074,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Created phi ");
-      print_gimple_stmt (dump_file, phi, 0, 0);
+      print_gimple_stmt (dump_file, phi, 0);
       fprintf (dump_file, " in block %d (%04d)\n", block->index, val);
     }
   pre_stats.phis++;
@@ -3262,7 +3250,6 @@ do_pre_regular_insertion (basic_block block, basic_block dom)
              gimple_stmt_iterator gsi = gsi_after_labels (block);
              gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
 
-             gimple_set_plf (assign, NECESSARY, false);
              VN_INFO_GET (temp)->value_id = val;
              VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
              if (VN_INFO (temp)->valnum == NULL_TREE)
@@ -3658,15 +3645,14 @@ compute_avail (void)
   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)
          || virtual_operand_p (name))
        continue;
@@ -3946,21 +3932,25 @@ compute_avail (void)
                        {
                          ref->set = set;
                          if (ref1->opcode == MEM_REF)
-                           ref1->op0 = fold_convert (TREE_TYPE (ref2->op0),
-                                                     ref1->op0);
+                           ref1->op0
+                             = wide_int_to_tree (TREE_TYPE (ref2->op0),
+                                                 wi::to_wide (ref1->op0));
                          else
-                           ref1->op2 = fold_convert (TREE_TYPE (ref2->op2),
-                                                     ref1->op2);
+                           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 = fold_convert (ptr_type_node,
-                                                     ref1->op0);
+                           ref1->op0
+                             = wide_int_to_tree (ptr_type_node,
+                                                 wi::to_wide (ref1->op0));
                          else
-                           ref1->op2 = fold_convert (ptr_type_node,
-                                                     ref1->op2);
+                           ref1->op2
+                             = wide_int_to_tree (ptr_type_node,
+                                                 wi::to_wide (ref1->op2));
                        }
                      operands.release ();
 
@@ -4009,872 +3999,6 @@ compute_avail (void)
 }
 
 
-/* Local state for the eliminate domwalk.  */
-static vec<gimple *> el_to_remove;
-static vec<gimple *> el_to_fixup;
-static unsigned int el_todo;
-static vec<tree> el_avail;
-static vec<tree> el_avail_stack;
-
-/* Return a leader for OP that is available at the current point of the
-   eliminate domwalk.  */
-
-static tree
-eliminate_avail (tree op)
-{
-  tree valnum = VN_INFO (op)->valnum;
-  if (TREE_CODE (valnum) == SSA_NAME)
-    {
-      if (SSA_NAME_IS_DEFAULT_DEF (valnum))
-       return valnum;
-      if (el_avail.length () > SSA_NAME_VERSION (valnum))
-       return el_avail[SSA_NAME_VERSION (valnum)];
-    }
-  else if (is_gimple_min_invariant (valnum))
-    return valnum;
-  return NULL_TREE;
-}
-
-/* At the current point of the eliminate domwalk make OP available.  */
-
-static void
-eliminate_push_avail (tree op)
-{
-  tree valnum = VN_INFO (op)->valnum;
-  if (TREE_CODE (valnum) == SSA_NAME)
-    {
-      if (el_avail.length () <= SSA_NAME_VERSION (valnum))
-       el_avail.safe_grow_cleared (SSA_NAME_VERSION (valnum) + 1);
-      tree pushop = op;
-      if (el_avail[SSA_NAME_VERSION (valnum)])
-       pushop = el_avail[SSA_NAME_VERSION (valnum)];
-      el_avail_stack.safe_push (pushop);
-      el_avail[SSA_NAME_VERSION (valnum)] = op;
-    }
-}
-
-/* Insert the expression recorded by SCCVN for VAL at *GSI.  Returns
-   the leader for the expression if insertion was successful.  */
-
-static tree
-eliminate_insert (gimple_stmt_iterator *gsi, tree val)
-{
-  gimple *stmt = gimple_seq_first_stmt (VN_INFO (val)->expr);
-  if (!is_gimple_assign (stmt)
-      || (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
-         && gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR
-         && gimple_assign_rhs_code (stmt) != BIT_FIELD_REF))
-    return NULL_TREE;
-
-  tree op = gimple_assign_rhs1 (stmt);
-  if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR
-      || gimple_assign_rhs_code (stmt) == BIT_FIELD_REF)
-    op = TREE_OPERAND (op, 0);
-  tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op;
-  if (!leader)
-    return NULL_TREE;
-
-  gimple_seq stmts = NULL;
-  tree res;
-  if (gimple_assign_rhs_code (stmt) == BIT_FIELD_REF)
-    res = gimple_build (&stmts, BIT_FIELD_REF,
-                       TREE_TYPE (val), leader,
-                       TREE_OPERAND (gimple_assign_rhs1 (stmt), 1),
-                       TREE_OPERAND (gimple_assign_rhs1 (stmt), 2));
-  else
-    res = gimple_build (&stmts, gimple_assign_rhs_code (stmt),
-                       TREE_TYPE (val), leader);
-  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-  VN_INFO_GET (res)->valnum = val;
-
-  if (TREE_CODE (leader) == SSA_NAME)
-    gimple_set_plf (SSA_NAME_DEF_STMT (leader), NECESSARY, true);
-
-  pre_stats.insertions++;
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "Inserted ");
-      print_gimple_stmt (dump_file, SSA_NAME_DEF_STMT (res), 0, 0);
-    }
-
-  return res;
-}
-
-class eliminate_dom_walker : public dom_walker
-{
-public:
-  eliminate_dom_walker (cdi_direction direction, bool do_pre_)
-      : dom_walker (direction), do_pre (do_pre_) {}
-
-  virtual edge before_dom_children (basic_block);
-  virtual void after_dom_children (basic_block);
-
-  bool do_pre;
-};
-
-/* Perform elimination for the basic-block B during the domwalk.  */
-
-edge
-eliminate_dom_walker::before_dom_children (basic_block b)
-{
-  /* Mark new bb.  */
-  el_avail_stack.safe_push (NULL_TREE);
-
-  /* ???  If we do nothing for unreachable blocks then this will confuse
-     tailmerging.  Eventually we can reduce its reliance on SCCVN now
-     that we fully copy/constant-propagate (most) things.  */
-
-  for (gphi_iterator gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
-    {
-      gphi *phi = gsi.phi ();
-      tree res = PHI_RESULT (phi);
-
-      if (virtual_operand_p (res))
-       {
-         gsi_next (&gsi);
-         continue;
-       }
-
-      tree sprime = eliminate_avail (res);
-      if (sprime
-         && sprime != res)
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "Replaced redundant PHI node defining ");
-             print_generic_expr (dump_file, res, 0);
-             fprintf (dump_file, " with ");
-             print_generic_expr (dump_file, sprime, 0);
-             fprintf (dump_file, "\n");
-           }
-
-         /* If we inserted this PHI node ourself, it's not an elimination.  */
-         if (inserted_exprs
-             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
-           pre_stats.phis--;
-         else
-           pre_stats.eliminations++;
-
-         /* If we will propagate into all uses don't bother to do
-            anything.  */
-         if (may_propagate_copy (res, sprime))
-           {
-             /* Mark the PHI for removal.  */
-             el_to_remove.safe_push (phi);
-             gsi_next (&gsi);
-             continue;
-           }
-
-         remove_phi_node (&gsi, false);
-
-         if (inserted_exprs
-             && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
-             && TREE_CODE (sprime) == SSA_NAME)
-           gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
-
-         if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
-           sprime = fold_convert (TREE_TYPE (res), sprime);
-         gimple *stmt = gimple_build_assign (res, sprime);
-         /* ???  It cannot yet be necessary (DOM walk).  */
-         gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
-
-         gimple_stmt_iterator gsi2 = gsi_after_labels (b);
-         gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
-         continue;
-       }
-
-      eliminate_push_avail (res);
-      gsi_next (&gsi);
-    }
-
-  for (gimple_stmt_iterator gsi = gsi_start_bb (b);
-       !gsi_end_p (gsi);
-       gsi_next (&gsi))
-    {
-      tree sprime = NULL_TREE;
-      gimple *stmt = gsi_stmt (gsi);
-      tree lhs = gimple_get_lhs (stmt);
-      if (lhs && TREE_CODE (lhs) == SSA_NAME
-         && !gimple_has_volatile_ops (stmt)
-         /* See PR43491.  Do not replace a global register variable when
-            it is a the RHS of an assignment.  Do replace local register
-            variables since gcc does not guarantee a local variable will
-            be allocated in register.
-            ???  The fix isn't effective here.  This should instead
-            be ensured by not value-numbering them the same but treating
-            them like volatiles?  */
-         && !(gimple_assign_single_p (stmt)
-              && (TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL
-                  && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))
-                  && is_global_var (gimple_assign_rhs1 (stmt)))))
-       {
-         sprime = eliminate_avail (lhs);
-         if (!sprime)
-           {
-             /* If there is no existing usable leader but SCCVN thinks
-                it has an expression it wants to use as replacement,
-                insert that.  */
-             tree val = VN_INFO (lhs)->valnum;
-             if (val != VN_TOP
-                 && TREE_CODE (val) == SSA_NAME
-                 && VN_INFO (val)->needs_insertion
-                 && VN_INFO (val)->expr != NULL
-                 && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
-               eliminate_push_avail (sprime);
-           }
-
-         /* If this now constitutes a copy duplicate points-to
-            and range info appropriately.  This is especially
-            important for inserted code.  See tree-ssa-copy.c
-            for similar code.  */
-         if (sprime
-             && TREE_CODE (sprime) == SSA_NAME)
-           {
-             basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
-             if (POINTER_TYPE_P (TREE_TYPE (lhs))
-                 && VN_INFO_PTR_INFO (lhs)
-                 && ! VN_INFO_PTR_INFO (sprime))
-               {
-                 duplicate_ssa_name_ptr_info (sprime,
-                                              VN_INFO_PTR_INFO (lhs));
-                 if (b != sprime_b)
-                   mark_ptr_info_alignment_unknown
-                       (SSA_NAME_PTR_INFO (sprime));
-               }
-             else if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
-                      && VN_INFO_RANGE_INFO (lhs)
-                      && ! VN_INFO_RANGE_INFO (sprime)
-                      && b == sprime_b)
-               duplicate_ssa_name_range_info (sprime,
-                                              VN_INFO_RANGE_TYPE (lhs),
-                                              VN_INFO_RANGE_INFO (lhs));
-           }
-
-         /* Inhibit the use of an inserted PHI on a loop header when
-            the address of the memory reference is a simple induction
-            variable.  In other cases the vectorizer won't do anything
-            anyway (either it's loop invariant or a complicated
-            expression).  */
-         if (sprime
-             && TREE_CODE (sprime) == SSA_NAME
-             && do_pre
-             && flag_tree_loop_vectorize
-             && loop_outer (b->loop_father)
-             && has_zero_uses (sprime)
-             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))
-             && gimple_assign_load_p (stmt))
-           {
-             gimple *def_stmt = SSA_NAME_DEF_STMT (sprime);
-             basic_block def_bb = gimple_bb (def_stmt);
-             if (gimple_code (def_stmt) == GIMPLE_PHI
-                 && def_bb->loop_father->header == def_bb)
-               {
-                 loop_p loop = def_bb->loop_father;
-                 ssa_op_iter iter;
-                 tree op;
-                 bool found = false;
-                 FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
-                   {
-                     affine_iv iv;
-                     def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
-                     if (def_bb
-                         && flow_bb_inside_loop_p (loop, def_bb)
-                         && simple_iv (loop, loop, op, &iv, true))
-                       {
-                         found = true;
-                         break;
-                       }
-                   }
-                 if (found)
-                   {
-                     if (dump_file && (dump_flags & TDF_DETAILS))
-                       {
-                         fprintf (dump_file, "Not replacing ");
-                         print_gimple_expr (dump_file, stmt, 0, 0);
-                         fprintf (dump_file, " with ");
-                         print_generic_expr (dump_file, sprime, 0);
-                         fprintf (dump_file, " which would add a loop"
-                                  " carried dependence to loop %d\n",
-                                  loop->num);
-                       }
-                     /* Don't keep sprime available.  */
-                     sprime = NULL_TREE;
-                   }
-               }
-           }
-
-         if (sprime)
-           {
-             /* If we can propagate the value computed for LHS into
-                all uses don't bother doing anything with this stmt.  */
-             if (may_propagate_copy (lhs, sprime))
-               {
-                 /* Mark it for removal.  */
-                 el_to_remove.safe_push (stmt);
-
-                 /* ???  Don't count copy/constant propagations.  */
-                 if (gimple_assign_single_p (stmt)
-                     && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-                         || gimple_assign_rhs1 (stmt) == sprime))
-                   continue;
-
-                 if (dump_file && (dump_flags & TDF_DETAILS))
-                   {
-                     fprintf (dump_file, "Replaced ");
-                     print_gimple_expr (dump_file, stmt, 0, 0);
-                     fprintf (dump_file, " with ");
-                     print_generic_expr (dump_file, sprime, 0);
-                     fprintf (dump_file, " in all uses of ");
-                     print_gimple_stmt (dump_file, stmt, 0, 0);
-                   }
-
-                 pre_stats.eliminations++;
-                 continue;
-               }
-
-             /* If this is an assignment from our leader (which
-                happens in the case the value-number is a constant)
-                then there is nothing to do.  */
-             if (gimple_assign_single_p (stmt)
-                 && sprime == gimple_assign_rhs1 (stmt))
-               continue;
-
-             /* Else replace its RHS.  */
-             bool can_make_abnormal_goto
-                 = is_gimple_call (stmt)
-                 && stmt_can_make_abnormal_goto (stmt);
-
-             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);
-
-             pre_stats.eliminations++;
-             gimple *orig_stmt = stmt;
-             if (!useless_type_conversion_p (TREE_TYPE (lhs),
-                                             TREE_TYPE (sprime)))
-               sprime = fold_convert (TREE_TYPE (lhs), sprime);
-             tree vdef = gimple_vdef (stmt);
-             tree vuse = gimple_vuse (stmt);
-             propagate_tree_value_into_stmt (&gsi, sprime);
-             stmt = gsi_stmt (gsi);
-             update_stmt (stmt);
-             if (vdef != gimple_vdef (stmt))
-               VN_INFO (vdef)->valnum = vuse;
-
-             /* If we removed EH side-effects from the statement, clean
-                its EH information.  */
-             if (maybe_clean_or_replace_eh_stmt (orig_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");
-               }
-
-             continue;
-           }
-       }
-
-      /* If the statement is a scalar store, see if the expression
-         has the same value number as its rhs.  If so, the store is
-         dead.  */
-      if (gimple_assign_single_p (stmt)
-         && !gimple_has_volatile_ops (stmt)
-         && !is_gimple_reg (gimple_assign_lhs (stmt))
-         && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-             || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
-        {
-          tree val;
-         tree rhs = gimple_assign_rhs1 (stmt);
-          val = vn_reference_lookup (gimple_assign_lhs (stmt),
-                                     gimple_vuse (stmt), VN_WALK, NULL, false);
-          if (TREE_CODE (rhs) == SSA_NAME)
-            rhs = VN_INFO (rhs)->valnum;
-          if (val
-              && operand_equal_p (val, rhs, 0))
-            {
-              if (dump_file && (dump_flags & TDF_DETAILS))
-                {
-                  fprintf (dump_file, "Deleted redundant store ");
-                  print_gimple_stmt (dump_file, stmt, 0, 0);
-                }
-
-              /* Queue stmt for removal.  */
-              el_to_remove.safe_push (stmt);
-             continue;
-            }
-       }
-
-      /* If this is a control statement value numbering left edges
-        unexecuted on force the condition in a way consistent with
-        that.  */
-      if (gcond *cond = dyn_cast <gcond *> (stmt))
-       {
-         if ((EDGE_SUCC (b, 0)->flags & EDGE_EXECUTABLE)
-             ^ (EDGE_SUCC (b, 1)->flags & EDGE_EXECUTABLE))
-           {
-              if (dump_file && (dump_flags & TDF_DETAILS))
-                {
-                  fprintf (dump_file, "Removing unexecutable edge from ");
-                  print_gimple_stmt (dump_file, stmt, 0, 0);
-                }
-             if (((EDGE_SUCC (b, 0)->flags & EDGE_TRUE_VALUE) != 0)
-                 == ((EDGE_SUCC (b, 0)->flags & EDGE_EXECUTABLE) != 0))
-               gimple_cond_make_true (cond);
-             else
-               gimple_cond_make_false (cond);
-             update_stmt (cond);
-             el_todo |= TODO_cleanup_cfg;
-             continue;
-           }
-       }
-
-      bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt);
-      bool was_noreturn = (is_gimple_call (stmt)
-                          && gimple_call_noreturn_p (stmt));
-      tree vdef = gimple_vdef (stmt);
-      tree vuse = gimple_vuse (stmt);
-
-      /* If we didn't replace the whole stmt (or propagate the result
-         into all uses), replace all uses on this stmt with their
-        leaders.  */
-      use_operand_p use_p;
-      ssa_op_iter iter;
-      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
-       {
-         tree use = USE_FROM_PTR (use_p);
-         /* ???  The call code above leaves stmt operands un-updated.  */
-         if (TREE_CODE (use) != SSA_NAME)
-           continue;
-         tree sprime = eliminate_avail (use);
-         if (sprime && sprime != use
-             && may_propagate_copy (use, sprime)
-             /* We substitute into debug stmts to avoid excessive
-                debug temporaries created by removed stmts, but we need
-                to avoid doing so for inserted sprimes as we never want
-                to create debug temporaries for them.  */
-             && (!inserted_exprs
-                 || TREE_CODE (sprime) != SSA_NAME
-                 || !is_gimple_debug (stmt)
-                 || !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
-           {
-             propagate_value (use_p, sprime);
-             gimple_set_modified (stmt, true);
-             if (TREE_CODE (sprime) == SSA_NAME
-                 && !is_gimple_debug (stmt))
-               gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
-                               NECESSARY, true);
-           }
-       }
-
-      /* Visit indirect calls and turn them into direct calls if
-        possible using the devirtualization machinery.  */
-      if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
-       {
-         tree fn = gimple_call_fn (call_stmt);
-         if (fn
-             && flag_devirtualize
-             && virtual_method_call_p (fn))
-           {
-             tree otr_type = obj_type_ref_class (fn);
-             tree instance;
-             ipa_polymorphic_call_context context (current_function_decl, fn, stmt, &instance);
-             bool final;
-
-             context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
-
-             vec <cgraph_node *>targets
-               = possible_polymorphic_call_targets (obj_type_ref_class (fn),
-                                                    tree_to_uhwi
-                                                      (OBJ_TYPE_REF_TOKEN (fn)),
-                                                    context,
-                                                    &final);
-             if (dump_file)
-               dump_possible_polymorphic_call_targets (dump_file, 
-                                                       obj_type_ref_class (fn),
-                                                       tree_to_uhwi
-                                                         (OBJ_TYPE_REF_TOKEN (fn)),
-                                                       context);
-             if (final && targets.length () <= 1 && dbg_cnt (devirt))
-               {
-                 tree fn;
-                 if (targets.length () == 1)
-                   fn = targets[0]->decl;
-                 else
-                   fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
-                 if (dump_enabled_p ())
-                   {
-                     location_t loc = gimple_location_safe (stmt);
-                     dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
-                                      "converting indirect call to "
-                                      "function %s\n",
-                                      lang_hooks.decl_printable_name (fn, 2));
-                   }
-                 gimple_call_set_fndecl (call_stmt, fn);
-                 maybe_remove_unused_call_args (cfun, call_stmt);
-                 gimple_set_modified (stmt, true);
-               }
-           }
-       }
-
-      if (gimple_modified_p (stmt))
-       {
-         /* If a formerly non-invariant ADDR_EXPR is turned into an
-            invariant one it was on a separate stmt.  */
-         if (gimple_assign_single_p (stmt)
-             && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
-           recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
-         gimple *old_stmt = stmt;
-         if (is_gimple_call (stmt))
-           {
-             /* ???  Only fold calls inplace for now, this may create new
-                SSA names which in turn will confuse free_scc_vn SSA name
-                release code.  */
-             fold_stmt_inplace (&gsi);
-             /* When changing a call into a noreturn call, cfg cleanup
-                is needed to fix up the noreturn call.  */
-             if (!was_noreturn && gimple_call_noreturn_p (stmt))
-               el_to_fixup.safe_push  (stmt);
-           }
-         else
-           {
-             fold_stmt (&gsi);
-             stmt = gsi_stmt (gsi);
-             if ((gimple_code (stmt) == GIMPLE_COND
-                  && (gimple_cond_true_p (as_a <gcond *> (stmt))
-                      || gimple_cond_false_p (as_a <gcond *> (stmt))))
-                 || (gimple_code (stmt) == GIMPLE_SWITCH
-                     && TREE_CODE (gimple_switch_index (
-                                     as_a <gswitch *> (stmt)))
-                        == INTEGER_CST))
-               el_todo |= TODO_cleanup_cfg;
-           }
-         /* If we removed EH side-effects from the statement, clean
-            its EH information.  */
-         if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
-           {
-             bitmap_set_bit (need_eh_cleanup,
-                             gimple_bb (stmt)->index);
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "  Removed EH side-effects.\n");
-           }
-         /* Likewise for AB side-effects.  */
-         if (can_make_abnormal_goto
-             && !stmt_can_make_abnormal_goto (stmt))
-           {
-             bitmap_set_bit (need_ab_cleanup,
-                             gimple_bb (stmt)->index);
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "  Removed AB side-effects.\n");
-           }
-         update_stmt (stmt);
-         if (vdef != gimple_vdef (stmt))
-           VN_INFO (vdef)->valnum = vuse;
-       }
-
-      /* Make new values available - for fully redundant LHS we
-         continue with the next stmt above and skip this.  */
-      def_operand_p defp;
-      FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF)
-       eliminate_push_avail (DEF_FROM_PTR (defp));
-    }
-
-  /* Replace destination PHI arguments.  */
-  edge_iterator ei;
-  edge e;
-  FOR_EACH_EDGE (e, ei, b->succs)
-    {
-      for (gphi_iterator gsi = gsi_start_phis (e->dest);
-          !gsi_end_p (gsi);
-          gsi_next (&gsi))
-       {
-         gphi *phi = gsi.phi ();
-         use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
-         tree arg = USE_FROM_PTR (use_p);
-         if (TREE_CODE (arg) != SSA_NAME
-             || virtual_operand_p (arg))
-           continue;
-         tree sprime = eliminate_avail (arg);
-         if (sprime && may_propagate_copy (arg, sprime))
-           {
-             propagate_value (use_p, sprime);
-             if (TREE_CODE (sprime) == SSA_NAME)
-               gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
-           }
-       }
-    }
-  return NULL;
-}
-
-/* Make no longer available leaders no longer available.  */
-
-void
-eliminate_dom_walker::after_dom_children (basic_block)
-{
-  tree entry;
-  while ((entry = el_avail_stack.pop ()) != NULL_TREE)
-    {
-      tree valnum = VN_INFO (entry)->valnum;
-      tree old = el_avail[SSA_NAME_VERSION (valnum)];
-      if (old == entry)
-       el_avail[SSA_NAME_VERSION (valnum)] = NULL_TREE;
-      else
-       el_avail[SSA_NAME_VERSION (valnum)] = entry;
-    }
-}
-
-/* Eliminate fully redundant computations.  */
-
-static unsigned int
-eliminate (bool do_pre)
-{
-  gimple_stmt_iterator gsi;
-  gimple *stmt;
-
-  need_eh_cleanup = BITMAP_ALLOC (NULL);
-  need_ab_cleanup = BITMAP_ALLOC (NULL);
-
-  el_to_remove.create (0);
-  el_to_fixup.create (0);
-  el_todo = 0;
-  el_avail.create (num_ssa_names);
-  el_avail_stack.create (0);
-
-  eliminate_dom_walker (CDI_DOMINATORS,
-                       do_pre).walk (cfun->cfg->x_entry_block_ptr);
-
-  el_avail.release ();
-  el_avail_stack.release ();
-
-  /* We cannot remove stmts during BB walk, especially not release SSA
-     names there as this confuses the VN machinery.  The stmts ending
-     up in el_to_remove are either stores or simple copies.
-     Remove stmts in reverse order to make debug stmt creation possible.  */
-  while (!el_to_remove.is_empty ())
-    {
-      stmt = el_to_remove.pop ();
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Removing dead stmt ");
-         print_gimple_stmt (dump_file, stmt, 0, 0);
-       }
-
-      tree lhs;
-      if (gimple_code (stmt) == GIMPLE_PHI)
-       lhs = gimple_phi_result (stmt);
-      else
-       lhs = gimple_get_lhs (stmt);
-
-      if (inserted_exprs
-         && TREE_CODE (lhs) == SSA_NAME)
-       bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
-
-      gsi = gsi_for_stmt (stmt);
-      if (gimple_code (stmt) == GIMPLE_PHI)
-       remove_phi_node (&gsi, true);
-      else
-       {
-         basic_block bb = gimple_bb (stmt);
-         unlink_stmt_vdef (stmt);
-         if (gsi_remove (&gsi, true))
-           bitmap_set_bit (need_eh_cleanup, bb->index);
-         if (is_gimple_call (stmt) && stmt_can_make_abnormal_goto (stmt))
-           bitmap_set_bit (need_ab_cleanup, bb->index);
-         release_defs (stmt);
-       }
-
-      /* Removing a stmt may expose a forwarder block.  */
-      el_todo |= TODO_cleanup_cfg;
-    }
-  el_to_remove.release ();
-
-  /* Fixup stmts that became noreturn calls.  This may require splitting
-     blocks and thus isn't possible during the dominator walk.  Do this
-     in reverse order so we don't inadvertedly remove a stmt we want to
-     fixup by visiting a dominating now noreturn call first.  */
-  while (!el_to_fixup.is_empty ())
-    {
-      stmt = el_to_fixup.pop ();
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Fixing up noreturn call ");
-         print_gimple_stmt (dump_file, stmt, 0, 0);
-       }
-
-      if (fixup_noreturn_call (stmt))
-       el_todo |= TODO_cleanup_cfg;
-    }
-  el_to_fixup.release ();
-
-  return el_todo;
-}
-
-/* Perform CFG cleanups made necessary by elimination.  */
-
-static unsigned 
-fini_eliminate (void)
-{
-  bool do_eh_cleanup = !bitmap_empty_p (need_eh_cleanup);
-  bool do_ab_cleanup = !bitmap_empty_p (need_ab_cleanup);
-
-  if (do_eh_cleanup)
-    gimple_purge_all_dead_eh_edges (need_eh_cleanup);
-
-  if (do_ab_cleanup)
-    gimple_purge_all_dead_abnormal_call_edges (need_ab_cleanup);
-
-  BITMAP_FREE (need_eh_cleanup);
-  BITMAP_FREE (need_ab_cleanup);
-
-  if (do_eh_cleanup || do_ab_cleanup)
-    return TODO_cleanup_cfg;
-  return 0;
-}
-
-/* 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
-   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.  */
-
-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)
-    {
-      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);
-      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)
-       {
-         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));
-               }
-           }
-       }
-      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));
-           }
-       }
-    }
-
-  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);
-}
-
-
 /* Initialize data structures used by PRE.  */
 
 static void
@@ -4917,6 +4041,7 @@ static void
 fini_pre ()
 {
   value_expressions.release ();
+  expressions.release ();
   BITMAP_FREE (inserted_exprs);
   bitmap_obstack_release (&grand_bitmap_obstack);
   bitmap_set_pool.release ();
@@ -4938,11 +4063,9 @@ const pass_data pass_data_pre =
   "pre", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
   TV_TREE_PRE, /* tv_id */
-  /* PROP_no_crit_edges is ensured by placing pass_split_crit_edges before
-     pass_pre.  */
-  ( PROP_no_crit_edges | PROP_cfg | PROP_ssa ), /* properties_required */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
   0, /* properties_provided */
-  PROP_no_crit_edges, /* properties_destroyed */
+  0, /* properties_destroyed */
   TODO_rebuild_alias, /* todo_flags_start */
   0, /* todo_flags_finish */
 };
@@ -4972,26 +4095,22 @@ pass_pre::execute (function *fun)
   /* This has to happen before SCCVN runs because
      loop_optimizer_init may create new phis, etc.  */
   loop_optimizer_init (LOOPS_NORMAL);
+  split_critical_edges ();
+  scev_initialize ();
 
-  if (!run_scc_vn (VN_WALK))
-    {
-      loop_optimizer_finalize ();
-      return 0;
-    }
+  run_scc_vn (VN_WALK);
 
   init_pre ();
-  scev_initialize ();
-
-  /* Collect and value number expressions computed in each basic block.  */
-  compute_avail ();
 
   /* 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.  */
+     computing ANTIC, either, even though it's plenty fast nor do
+     we require AVAIL.  */
   if (n_basic_blocks_for_fn (fun) < 4000)
     {
+      compute_avail ();
       compute_antic ();
       insert ();
     }
@@ -5006,21 +4125,23 @@ pass_pre::execute (function *fun)
      not keeping virtual operands up-to-date.  */
   gcc_assert (!need_ssa_update_p (fun));
 
-  /* Remove all the redundant expressions.  */
-  todo |= eliminate (true);
-
   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);
-  statistics_counter_event (fun, "Eliminated", pre_stats.eliminations);
 
-  clear_expression_ids ();
-  remove_dead_inserted_code ();
+  /* Remove all the redundant expressions.  */
+  todo |= vn_eliminate (inserted_exprs);
+
+  /* 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.  */
+  simple_dce_from_worklist (inserted_exprs);
 
-  scev_finalize ();
   fini_pre ();
-  todo |= fini_eliminate ();
+
+  scev_finalize ();
   loop_optimizer_finalize ();
 
   /* Restore SSA info before tail-merging as that resets it as well.  */
@@ -5054,64 +4175,3 @@ make_pass_pre (gcc::context *ctxt)
 {
   return new pass_pre (ctxt);
 }
-
-namespace {
-
-const pass_data pass_data_fre =
-{
-  GIMPLE_PASS, /* type */
-  "fre", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_TREE_FRE, /* tv_id */
-  ( PROP_cfg | PROP_ssa ), /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
-
-class pass_fre : public gimple_opt_pass
-{
-public:
-  pass_fre (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_fre, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  opt_pass * clone () { return new pass_fre (m_ctxt); }
-  virtual bool gate (function *) { return flag_tree_fre != 0; }
-  virtual unsigned int execute (function *);
-
-}; // class pass_fre
-
-unsigned int
-pass_fre::execute (function *fun)
-{
-  unsigned int todo = 0;
-
-  if (!run_scc_vn (VN_WALKREWRITE))
-    return 0;
-
-  memset (&pre_stats, 0, sizeof (pre_stats));
-
-  /* Remove all the redundant expressions.  */
-  todo |= eliminate (false);
-
-  todo |= fini_eliminate ();
-
-  scc_vn_restore_ssa_info ();
-  free_scc_vn ();
-
-  statistics_counter_event (fun, "Insertions", pre_stats.insertions);
-  statistics_counter_event (fun, "Eliminated", pre_stats.eliminations);
-
-  return todo;
-}
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_fre (gcc::context *ctxt)
-{
-  return new pass_fre (ctxt);
-}