OSDN Git Service

2009-05-29 Kai Tietz <kai.tietz@onevision.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-pre.c
index 18c442e..fc311bc 100644 (file)
@@ -377,6 +377,9 @@ typedef struct bb_bitmap_sets
      the current iteration.  */
   bitmap_set_t new_sets;
 
+  /* A cache for value_dies_in_block_x.  */
+  bitmap expr_dies;
+
   /* True if we have visited this block during ANTIC calculation.  */
   unsigned int visited:1;
 
@@ -392,7 +395,8 @@ typedef struct bb_bitmap_sets
 #define ANTIC_IN(BB)   ((bb_value_sets_t) ((BB)->aux))->antic_in
 #define PA_IN(BB)      ((bb_value_sets_t) ((BB)->aux))->pa_in
 #define NEW_SETS(BB)   ((bb_value_sets_t) ((BB)->aux))->new_sets
-#define BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited
+#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
 
 
@@ -906,26 +910,42 @@ print_pre_expr (FILE *outfile, const pre_expr expr)
             VEC_iterate (vn_reference_op_s, ref->operands, 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", tree_code_name [vro->opcode]);
+               if (vro->op0)
+                 {
+                   fprintf (outfile, "<");
+                   closebrace = true;
+                 }
+             }
            if (vro->op0)
              {
-               if (vro->op1)
-                 fprintf (outfile, "<");
                print_generic_expr (outfile, vro->op0, 0);
                if (vro->op1)
                  {
                    fprintf (outfile, ",");
                    print_generic_expr (outfile, vro->op1, 0);
                  }
-               if (vro->op1)
-                 fprintf (outfile, ">");
+               if (vro->op2)
+                 {
+                   fprintf (outfile, ",");
+                   print_generic_expr (outfile, vro->op2, 0);
+                 }
              }
+           if (closebrace)
+               fprintf (outfile, ">");
            if (i != VEC_length (vn_reference_op_s, ref->operands) - 1)
              fprintf (outfile, ",");
          }
        fprintf (outfile, "}");
+       if (ref->vuse)
+         {
+           fprintf (outfile, "@");
+           print_generic_expr (outfile, ref->vuse, 0);
+         }
       }
       break;
     }
@@ -1051,7 +1071,9 @@ get_or_alloc_expr_for (tree t)
 {
   if (TREE_CODE (t) == SSA_NAME)
     return get_or_alloc_expr_for_name (t);
-  else if (is_gimple_min_invariant (t))
+  else if (is_gimple_min_invariant (t)
+          || TREE_CODE (t) == EXC_PTR_EXPR
+          || TREE_CODE (t) == FILTER_EXPR)
     return get_or_alloc_expr_for_constant (t);
   else
     {
@@ -1225,48 +1247,47 @@ do_unary:
   return e;
 }
 
-/* Translate the vuses in the VUSES vector backwards through phi nodes
-   in PHIBLOCK, so that they have the value they would have in
-   BLOCK. */
+/* Translate the VUSE backwards through phi nodes in PHIBLOCK, so that
+   it has the value it would have in BLOCK.  */
 
-static VEC(tree, gc) *
-translate_vuses_through_block (VEC (tree, gc) *vuses,
-                              basic_block phiblock,
-                              basic_block block)
+static tree
+translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
+                             alias_set_type set, tree type, tree vuse,
+                             basic_block phiblock,
+                             basic_block block)
 {
-  tree oldvuse;
-  VEC(tree, gc) *result = NULL;
-  int i;
+  gimple phi = SSA_NAME_DEF_STMT (vuse);
+  ao_ref ref;
+
+  if (gimple_bb (phi) != phiblock)
+    return vuse;
 
-  for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); i++)
+  if (gimple_code (phi) == GIMPLE_PHI)
     {
-      gimple phi = SSA_NAME_DEF_STMT (oldvuse);
-      if (gimple_code (phi) == GIMPLE_PHI
-         && gimple_bb (phi) == phiblock)
-       {
-         edge e = find_edge (block, gimple_bb (phi));
-         if (e)
-           {
-             tree def = PHI_ARG_DEF (phi, e->dest_idx);
-             if (def != oldvuse)
-               {
-                 if (!result)
-                   result = VEC_copy (tree, gc, vuses);
-                 VEC_replace (tree, result, i, def);
-               }
-           }
-       }
+      edge e = find_edge (block, phiblock);
+      return PHI_ARG_DEF (phi, e->dest_idx);
     }
 
-  /* We avoid creating a new copy of the vuses unless something
-     actually changed, so result can be NULL.  */
-  if (result)
+  if (!ao_ref_init_from_vn_reference (&ref, set, type, operands))
+    return NULL_TREE;
+
+  /* Use the alias-oracle to find either the PHI node in this block,
+     the first VUSE used in this block that is equivalent to vuse or
+     the first VUSE which definition in this block kills the value.  */
+  while (!stmt_may_clobber_ref_p_1 (phi, &ref))
     {
-      sort_vuses (result);
-      return result;
+      vuse = gimple_vuse (phi);
+      phi = SSA_NAME_DEF_STMT (vuse);
+      if (gimple_bb (phi) != phiblock)
+       return vuse;
+      if (gimple_code (phi) == GIMPLE_PHI)
+       {
+         edge e = find_edge (block, phiblock);
+         return PHI_ARG_DEF (phi, e->dest_idx);
+       }
     }
-  return vuses;
 
+  return NULL_TREE;
 }
 
 /* Like find_leader, but checks for the value existing in SET1 *or*
@@ -1296,23 +1317,7 @@ get_expr_type (const pre_expr e)
     case CONSTANT:
       return TREE_TYPE (PRE_EXPR_CONSTANT (e));
     case REFERENCE:
-      {
-       vn_reference_op_t vro;
-
-       gcc_assert (PRE_EXPR_REFERENCE (e)->operands);
-       vro = VEC_index (vn_reference_op_s,
-                        PRE_EXPR_REFERENCE (e)->operands,
-                        0);
-       /* We don't store type along with COMPONENT_REF because it is
-          always the same as FIELD_DECL's type.  */
-       if (!vro->type)
-         {
-           gcc_assert (vro->opcode == COMPONENT_REF);
-           return TREE_TYPE (vro->op0);
-         }
-       return vro->type;
-      }
-
+      return PRE_EXPR_REFERENCE (e)->type;
     case NARY:
       return PRE_EXPR_NARY (e)->type;
     }
@@ -1538,15 +1543,16 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
       {
        vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
        VEC (vn_reference_op_s, heap) *operands = ref->operands;
-       VEC (tree, gc) *vuses = ref->vuses;
-       VEC (tree, gc) *newvuses = vuses;
+       tree vuse = ref->vuse;
+       tree newvuse = vuse;
        VEC (vn_reference_op_s, heap) *newoperands = NULL;
        bool changed = false;
-       unsigned int i;
+       unsigned int i, j;
        vn_reference_op_t operand;
        vn_reference_t newref;
 
-       for (i = 0; VEC_iterate (vn_reference_op_s, operands, i, operand); i++)
+       for (i = 0, j = 0;
+            VEC_iterate (vn_reference_op_s, operands, i, operand); i++, j++)
          {
            pre_expr opresult;
            pre_expr leader;
@@ -1621,7 +1627,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            newop.op0 = op0;
            newop.op1 = op1;
            newop.op2 = op2;
-           VEC_replace (vn_reference_op_s, newoperands, i, &newop);
+           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 == INDIRECT_REF)
+             vn_reference_fold_indirect (&newoperands, &j);
          }
        if (i != VEC_length (vn_reference_op_s, operands))
          {
@@ -1630,15 +1642,26 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            return NULL;
          }
 
-       newvuses = translate_vuses_through_block (vuses, phiblock, pred);
-       changed |= newvuses != vuses;
+       if (vuse)
+         {
+           newvuse = translate_vuse_through_block (newoperands,
+                                                   ref->set, ref->type,
+                                                   vuse, phiblock, pred);
+           if (newvuse == NULL_TREE)
+             {
+               VEC_free (vn_reference_op_s, heap, newoperands);
+               return NULL;
+             }
+         }
+       changed |= newvuse != vuse;
 
        if (changed)
          {
            unsigned int new_val_id;
            pre_expr constant;
 
-           tree result = vn_reference_lookup_pieces (newvuses,
+           tree result = vn_reference_lookup_pieces (newvuse, ref->set,
+                                                     ref->type,
                                                      newoperands,
                                                      &newref, true);
            if (newref)
@@ -1669,7 +1692,8 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                new_val_id = get_next_value_id ();
                VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
                                       get_max_value_id() + 1);
-               newref = vn_reference_insert_pieces (newvuses,
+               newref = vn_reference_insert_pieces (newvuse, ref->set,
+                                                    ref->type,
                                                     newoperands,
                                                     result, new_val_id);
                newoperands = NULL;
@@ -1844,24 +1868,73 @@ bitmap_find_leader (bitmap_set_t set, unsigned int val, gimple stmt)
 static bool
 value_dies_in_block_x (pre_expr expr, basic_block block)
 {
-  int i;
-  tree vuse;
-  VEC (tree, gc) *vuses = PRE_EXPR_REFERENCE (expr)->vuses;
+  tree vuse = PRE_EXPR_REFERENCE (expr)->vuse;
+  vn_reference_t refx = PRE_EXPR_REFERENCE (expr);
+  gimple def;
+  gimple_stmt_iterator gsi;
+  unsigned id = get_expression_id (expr);
+  bool res = false;
+  ao_ref ref;
+
+  if (!vuse)
+    return false;
 
-  /* Conservatively, a value dies if it's vuses are defined in this
-     block, unless they come from phi nodes (which are merge operations,
-     rather than stores.  */
-  for (i = 0; VEC_iterate (tree, vuses, i, vuse); i++)
+  /* Lookup a previously calculated result.  */
+  if (EXPR_DIES (block)
+      && bitmap_bit_p (EXPR_DIES (block), id * 2))
+    return bitmap_bit_p (EXPR_DIES (block), id * 2 + 1);
+
+  /* A memory expression {e, VUSE} dies in the block if there is a
+     statement that may clobber e.  If, starting statement walk from the
+     top of the basic block, a statement uses VUSE there can be no kill
+     inbetween that use and the original statement that loaded {e, VUSE},
+     so we can stop walking.  */
+  ref.base = NULL_TREE;
+  for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      gimple def = SSA_NAME_DEF_STMT (vuse);
+      tree def_vuse, def_vdef;
+      def = gsi_stmt (gsi);
+      def_vuse = gimple_vuse (def);
+      def_vdef = gimple_vdef (def);
 
-      if (gimple_bb (def) != block)
+      /* Not a memory statement.  */
+      if (!def_vuse)
        continue;
-      if (gimple_code (def) == GIMPLE_PHI)
-       continue;
-      return true;
+
+      /* Not a may-def.  */
+      if (!def_vdef)
+       {
+         /* A load with the same VUSE, we're done.  */
+         if (def_vuse == vuse)
+           break;
+
+         continue;
+       }
+
+      /* Init ref only if we really need it.  */
+      if (ref.base == NULL_TREE
+         && !ao_ref_init_from_vn_reference (&ref, refx->set, refx->type,
+                                            refx->operands))
+       {
+         res = true;
+         break;
+       }
+      /* If the statement may clobber expr, it dies.  */
+      if (stmt_may_clobber_ref_p_1 (def, &ref))
+       {
+         res = true;
+         break;
+       }
     }
-  return false;
+
+  /* Remember the result.  */
+  if (!EXPR_DIES (block))
+    EXPR_DIES (block) = BITMAP_ALLOC (&grand_bitmap_obstack);
+  bitmap_set_bit (EXPR_DIES (block), id * 2);
+  if (res)
+    bitmap_set_bit (EXPR_DIES (block), id * 2 + 1);
+
+  return res;
 }
 
 
@@ -1923,7 +1996,7 @@ vro_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2,
    ONLY SET2 CAN BE NULL.
    This means that we have a leader for each part of the expression
    (if it consists of values), or the expression is an SSA_NAME.
-   For loads/calls, we also see if the vuses are killed in this block.
+   For loads/calls, we also see if the vuse is killed in this block.
 */
 
 static bool
@@ -1968,6 +2041,15 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr,
            if (!vro_valid_in_sets (set1, set2, vro))
              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);
       }
     default:
@@ -2502,6 +2584,7 @@ can_PRE_operation (tree op)
    for performing quick dead code elimination of insertions we made
    that didn't turn out to be necessary.   */
 static VEC(gimple,heap) *inserted_exprs;
+static bitmap inserted_phi_names;
 
 /* Pool allocated fake store expressions are placed onto this
    worklist, which, after performing dead code elimination, is walked
@@ -2551,6 +2634,36 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
        return folded;
       }
       break;
+    case TARGET_MEM_REF:
+      {
+       vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands,
+                                             *operand);
+       pre_expr op0expr;
+       tree genop0 = NULL_TREE;
+       tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
+                                                       stmts, domstmt);
+       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);
+           if (!genop0)
+             return NULL_TREE;
+         }
+       if (DECL_P (baseop))
+         return build6 (TARGET_MEM_REF, currop->type,
+                        baseop, NULL_TREE,
+                        genop0, currop->op1, currop->op2,
+                        unshare_expr (nextop->op1));
+       else
+         return build6 (TARGET_MEM_REF, currop->type,
+                        NULL_TREE, baseop,
+                        genop0, currop->op1, currop->op2,
+                        unshare_expr (nextop->op1));
+      }
+      break;
     case ADDR_EXPR:
       if (currop->op0)
        {
@@ -2806,8 +2919,8 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
                             gimple_seq *stmts, gimple domstmt, tree type)
 {
   tree temp, name;
-  tree folded, newexpr;
-  gimple_seq forced_stmts;
+  tree folded;
+  gimple_seq forced_stmts = NULL;
   unsigned int value_id;
   gimple_stmt_iterator gsi;
   tree exprtype = type ? type : get_expr_type (expr);
@@ -2879,13 +2992,16 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
     default:
       return NULL_TREE;
     }
-  folded = fold_convert (exprtype, 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.  */
-  newexpr = force_gimple_operand (unshare_expr (folded), &forced_stmts,
-                                 false, NULL);
+  folded = force_gimple_operand (unshare_expr (folded), &forced_stmts,
+                                false, NULL);
 
   /* If we have any intermediate expressions to the value sets, add them
      to the value sets and chain them in the instruction stream.  */
@@ -2929,7 +3045,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
       || TREE_CODE (exprtype) == VECTOR_TYPE)
     DECL_GIMPLE_REG_P (temp) = 1;
 
-  newstmt = gimple_build_assign (temp, newexpr);
+  newstmt = gimple_build_assign (temp, folded);
   name = make_ssa_name (temp, newstmt);
   gimple_assign_set_lhs (newstmt, name);
   gimple_set_plf (newstmt, NECESSARY, false);
@@ -3147,6 +3263,8 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
   VN_INFO_GET (gimple_phi_result (phi))->valnum = gimple_phi_result (phi);
   VN_INFO (gimple_phi_result (phi))->value_id = val;
   VEC_safe_push (gimple, heap, inserted_exprs, phi);
+  bitmap_set_bit (inserted_phi_names,
+                 SSA_NAME_VERSION (gimple_phi_result (phi)));
   FOR_EACH_EDGE (pred, ei, block->preds)
     {
       pre_expr ae = avail[pred->src->index];
@@ -3564,46 +3682,28 @@ compute_avail (void)
   basic_block block, son;
   basic_block *worklist;
   size_t sp = 0;
-  tree param;
+  unsigned i;
 
-  /* For arguments with default definitions, we pretend they are
-     defined in the entry block.  */
-  for (param = DECL_ARGUMENTS (current_function_decl);
-       param;
-       param = TREE_CHAIN (param))
+  /* 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)
     {
-      if (gimple_default_def (cfun, param) != NULL)
-       {
-         tree def = gimple_default_def (cfun, param);
-         pre_expr e = get_or_alloc_expr_for_name (def);
-
-         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 (maximal_set, e);
-           }
-         bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
-       }
-    }
+      tree name = ssa_name (i);
+      pre_expr e;
+      if (!name
+         || !SSA_NAME_IS_DEFAULT_DEF (name)
+         || has_zero_uses (name)
+         || !is_gimple_reg (name))
+       continue;
 
-  /* Likewise for the static chain decl. */
-  if (cfun->static_chain_decl)
-    {
-      param = cfun->static_chain_decl;
-      if (gimple_default_def (cfun, param) != NULL)
+      e = get_or_alloc_expr_for_name (name);
+      add_to_value (get_expr_value_id (e), e);
+      if (!in_fre)
        {
-         tree def = gimple_default_def (cfun, param);
-         pre_expr e = get_or_alloc_expr_for_name (def);
-
-         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 (maximal_set, e);
-           }
-         bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
+         bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e);
+         bitmap_value_insert_into_set (maximal_set, e);
        }
+      bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
     }
 
   /* Allocate the worklist.  */
@@ -3680,7 +3780,8 @@ compute_avail (void)
                  continue;
 
                copy_reference_ops_from_call (stmt, &ops);
-               vn_reference_lookup_pieces (shared_vuses_from_stmt (stmt),
+               vn_reference_lookup_pieces (gimple_vuse (stmt), 0,
+                                           gimple_expr_type (stmt),
                                            ops, &ref, false);
                VEC_free (vn_reference_op_s, heap, ops);
                if (!ref)
@@ -3756,7 +3857,7 @@ compute_avail (void)
                      vn_reference_op_t vro;
 
                      vn_reference_lookup (gimple_assign_rhs1 (stmt),
-                                          shared_vuses_from_stmt (stmt),
+                                          gimple_vuse (stmt),
                                           false, &ref);
                      if (!ref)
                        continue;
@@ -3850,16 +3951,18 @@ do_SCCVN_insertion (gimple stmt, tree ssa_vn)
 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)
     {
-      gimple_stmt_iterator i;
-
-      for (i = gsi_start_bb (b); !gsi_end_p (i);)
+      for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         gimple stmt = gsi_stmt (i);
+         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
@@ -3899,8 +4002,10 @@ eliminate (void)
                 value is constant, use that constant.  */
              if (!sprime && is_gimple_min_invariant (VN_INFO (lhs)->valnum))
                {
-                 sprime = fold_convert (TREE_TYPE (lhs),
-                                        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))
                    {
@@ -3912,10 +4017,9 @@ eliminate (void)
                      print_gimple_stmt (dump_file, stmt, 0, 0);
                    }
                  pre_stats.eliminations++;
-                 propagate_tree_value_into_stmt (&i, sprime);
-                 stmt = gsi_stmt (i);
+                 propagate_tree_value_into_stmt (&gsi, sprime);
+                 stmt = gsi_stmt (gsi);
                  update_stmt (stmt);
-                 gsi_next (&i);
                  continue;
                }
 
@@ -3961,8 +4065,8 @@ eliminate (void)
                    sprime = fold_convert (gimple_expr_type (stmt), sprime);
 
                  pre_stats.eliminations++;
-                 propagate_tree_value_into_stmt (&i, sprime);
-                 stmt = gsi_stmt (i);
+                 propagate_tree_value_into_stmt (&gsi, sprime);
+                 stmt = gsi_stmt (gsi);
                  update_stmt (stmt);
 
                  /* If we removed EH side effects from the statement, clean
@@ -3987,45 +4091,20 @@ eliminate (void)
              tree rhs = gimple_assign_rhs1 (stmt);
              tree val;
              val = vn_reference_lookup (gimple_assign_lhs (stmt),
-                                        shared_vuses_from_stmt (stmt),
-                                        true, NULL);
+                                        gimple_vuse (stmt), true, NULL);
              if (TREE_CODE (rhs) == SSA_NAME)
                rhs = VN_INFO (rhs)->valnum;
              if (val
                  && operand_equal_p (val, rhs, 0))
                {
-                 def_operand_p def;
-                 use_operand_p use;
-                 vuse_vec_p usevec;
-                 ssa_op_iter oi;
-                 imm_use_iterator ui;
-                 gimple use_stmt;
-
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    {
-                     fprintf (dump_file, "Deleted dead store ");
+                     fprintf (dump_file, "Deleted redundant store ");
                      print_gimple_stmt (dump_file, stmt, 0, 0);
                    }
 
-                 /* Propagate all may-uses to the uses of their defs.  */
-                 FOR_EACH_SSA_VDEF_OPERAND (def, usevec, stmt, oi)
-                   {
-                     tree vuse = VUSE_ELEMENT_VAR (*usevec, 0);
-                     tree vdef = DEF_FROM_PTR (def);
-
-                     /* If the vdef is used in an abnormal PHI node we
-                        have to propagate that flag to the vuse as well.  */
-                     if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vdef))
-                       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vuse) = 1;
-
-                     FOR_EACH_IMM_USE_STMT (use_stmt, ui, vdef)
-                       FOR_EACH_IMM_USE_ON_STMT (use, ui)
-                         SET_USE (use, vuse);
-                   }
-
-                 gsi_remove (&i, true);
-                 release_defs (stmt);
-                 continue;
+                 /* Queue stmt for removal.  */
+                 VEC_safe_push (gimple, heap, to_remove, stmt);
                }
            }
          /* Visit COND_EXPRs and fold the comparison with the
@@ -4052,10 +4131,130 @@ eliminate (void)
                  todo = TODO_cleanup_cfg;
                }
            }
+         /* Visit indirect calls and turn them into direct calls if
+            possible.  */
+         if (gimple_code (stmt) == GIMPLE_CALL
+             && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
+           {
+             tree fn = VN_INFO (gimple_call_fn (stmt))->valnum;
+             if (TREE_CODE (fn) == ADDR_EXPR
+                 && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
+               {
+                 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);
+                 if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
+                   gimple_purge_dead_eh_edges (b);
+
+                 /* 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;
+               }
+           }
+       }
 
-         gsi_next (&i);
+      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)
+             || bitmap_bit_p (inserted_phi_names, SSA_NAME_VERSION (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 (!sprimeexpr
+             || 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 (!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;
+         if (TREE_CODE (sprime) == SSA_NAME)
+           gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
+                           NECESSARY, true);
+         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);
+         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 (i = 0; VEC_iterate (gimple, to_remove, i, stmt); ++i)
+    {
+      tree lhs = gimple_assign_lhs (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
+         && single_imm_use (lhs, &use_p, &use_stmt)
+         && may_propagate_copy (USE_FROM_PTR (use_p),
+                                gimple_assign_rhs1 (stmt)))
+       {
+         SET_USE (use_p, gimple_assign_rhs1 (stmt));
+         update_stmt (use_stmt);
+       }
+
+      /* If this is a store or a now unused copy, remove it.  */
+      if (TREE_CODE (lhs) != SSA_NAME
+         || has_zero_uses (lhs))
+       {
+         gsi = gsi_for_stmt (stmt);
+         unlink_stmt_vdef (stmt);
+         gsi_remove (&gsi, true);
+         release_defs (stmt);
        }
     }
+  VEC_free (gimple, heap, to_remove);
 
   return todo;
 }
@@ -4211,6 +4410,7 @@ init_pre (bool do_fre)
   calculate_dominance_info (CDI_DOMINATORS);
 
   bitmap_obstack_initialize (&grand_bitmap_obstack);
+  inserted_phi_names = BITMAP_ALLOC (&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,
@@ -4357,7 +4557,7 @@ execute_pre (bool do_fre ATTRIBUTE_UNUSED)
 static unsigned int
 do_pre (void)
 {
-  return TODO_rebuild_alias | execute_pre (false);
+  return execute_pre (false);
 }
 
 static bool
@@ -4379,10 +4579,10 @@ struct gimple_opt_pass pass_pre =
   0,                                   /* static_pass_number */
   TV_TREE_PRE,                         /* tv_id */
   PROP_no_crit_edges | PROP_cfg
-    | PROP_ssa | PROP_alias,           /* properties_required */
+    | PROP_ssa,                                /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
+  TODO_rebuild_alias,                  /* todo_flags_start */
   TODO_update_ssa_only_virtuals | TODO_dump_func | TODO_ggc_collect
   | TODO_verify_ssa /* todo_flags_finish */
  }
@@ -4414,7 +4614,7 @@ struct gimple_opt_pass pass_fre =
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
   TV_TREE_FRE,                         /* tv_id */
-  PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
+  PROP_cfg | PROP_ssa,                 /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */