OSDN Git Service

dbgcnt name matching bug fix
[pf3gnuchains/gcc-fork.git] / gcc / tree-outof-ssa.c
index 1fef266..4ed8e9f 100644 (file)
@@ -1,12 +1,12 @@
 /* Convert a program in SSA form into Normal form.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Andrew Macleod <amacleod@redhat.com>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,38 +15,26 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "flags.h"
-#include "rtl.h"
-#include "tm_p.h"
 #include "ggc.h"
-#include "langhooks.h"
-#include "hard-reg-set.h"
 #include "basic-block.h"
-#include "output.h"
-#include "errors.h"
-#include "expr.h"
-#include "function.h"
 #include "diagnostic.h"
 #include "bitmap.h"
 #include "tree-flow.h"
-#include "tree-gimple.h"
-#include "tree-inline.h"
-#include "varray.h"
 #include "timevar.h"
-#include "tree-alias-common.h"
-#include "hashtab.h"
 #include "tree-dump.h"
-#include "tree-ssa-live.h"
 #include "tree-pass.h"
+#include "toplev.h"
+#include "expr.h"
+#include "ssaexpand.h"
+
 
 /* Used to hold all the components required to do SSA PHI elimination.
    The node and pred/succ list is a simple linear list of nodes and
@@ -74,16 +62,16 @@ typedef struct _elim_graph {
   int size;
 
   /* List of nodes in the elimination graph.  */
-  varray_type nodes;
+  VEC(int,heap) *nodes;
 
   /*  The predecessor and successor edge list.  */
-  varray_type edge_list;
+  VEC(int,heap) *edge_list;
 
   /* Visited vector.  */
   sbitmap visited;
 
   /* Stack for visited nodes.  */
-  varray_type stack;
+  VEC(int,heap) *stack;
   
   /* The variable partition map.  */
   var_map map;
@@ -92,106 +80,194 @@ typedef struct _elim_graph {
   edge e;
 
   /* List of constant copies to emit.  These are pushed on in pairs.  */
-  varray_type  const_copies;
+  VEC(int,heap) *const_dests;
+  VEC(tree,heap) *const_copies;
 } *elim_graph;
 
 
-/* Local functions.  */
-static tree create_temp (tree);
-static void insert_copy_on_edge (edge, tree, tree);
-static elim_graph new_elim_graph (int);
-static inline void delete_elim_graph (elim_graph);
-static inline void clear_elim_graph (elim_graph);
-static inline int elim_graph_size (elim_graph);
-static inline void elim_graph_add_node (elim_graph, tree);
-static inline void elim_graph_add_edge (elim_graph, int, int);
-static inline int elim_graph_remove_succ_edge (elim_graph, int);
-
-static inline void eliminate_name (elim_graph, tree);
-static void eliminate_build (elim_graph, basic_block, int);
-static void elim_forward (elim_graph, int);
-static int elim_unvisited_predecessor (elim_graph, int);
-static void elim_backward (elim_graph, int);
-static void elim_create (elim_graph, int);
-static void eliminate_phi (edge, int, elim_graph);
-static tree_live_info_p coalesce_ssa_name (var_map, int);
-static void assign_vars (var_map);
-static bool replace_use_variable (var_map, use_operand_p, tree *);
-static bool replace_def_variable (var_map, def_operand_p, tree *);
-static void eliminate_virtual_phis (void);
-static void coalesce_abnormal_edges (var_map, conflict_graph, root_var_p);
-static void print_exprs (FILE *, const char *, tree, const char *, tree,
-                        const char *);
-static void print_exprs_edge (FILE *, edge, const char *, tree, const char *,
-                             tree);
-
-
-/* Create a temporary variable based on the type of variable T.  Use T's name
-   as the prefix.  */
-
-static tree
-create_temp (tree t)
+/* For an edge E find out a good source location to associate with
+   instructions inserted on edge E.  If E has an implicit goto set,
+   use its location.  Otherwise search instructions in predecessors
+   of E for a location, and use that one.  That makes sense because
+   we insert on edges for PHI nodes, and effects of PHIs happen on
+   the end of the predecessor conceptually.  */
+
+static void
+set_location_for_edge (edge e)
 {
-  tree tmp;
-  const char *name = NULL;
-  tree type;
+  if (e->goto_locus)
+    {
+      set_curr_insn_source_location (e->goto_locus);
+      set_curr_insn_block (e->goto_block);
+    }
+  else
+    {
+      basic_block bb = e->src;
+      gimple_stmt_iterator gsi;
 
-  if (TREE_CODE (t) == SSA_NAME)
-    t = SSA_NAME_VAR (t);
-  if (TREE_CODE (t) != VAR_DECL 
-      && TREE_CODE (t) != PARM_DECL)
-    abort ();
-
-  type = TREE_TYPE (t);
-  tmp = DECL_NAME (t);
-  if (tmp)
-    name = IDENTIFIER_POINTER (tmp);
-
-  if (name == NULL)
-    name = "temp";
-  tmp = create_tmp_var (type, name);
-  DECL_ARTIFICIAL (tmp) = DECL_ARTIFICIAL (t);
-  add_referenced_tmp_var (tmp);
-
-  /* add_referenced_tmp_var will create the annotation and set up some
-     of the flags in the annotation.  However, some flags we need to
-     inherit from our original variable.  */
-  var_ann (tmp)->type_mem_tag = var_ann (t)->type_mem_tag;
-  if (is_call_clobbered (t))
-    mark_call_clobbered (tmp);
-
-  return tmp;
+      do
+       {
+         for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
+           {
+             gimple stmt = gsi_stmt (gsi);
+             if (gimple_has_location (stmt) || gimple_block (stmt))
+               {
+                 set_curr_insn_source_location (gimple_location (stmt));
+                 set_curr_insn_block (gimple_block (stmt));
+                 return;
+               }
+           }
+         /* Nothing found in this basic block.  Make a half-assed attempt
+            to continue with another block.  */
+         if (single_pred_p (bb))
+           bb = single_pred (bb);
+         else
+           bb = e->src;
+       }
+      while (bb != e->src);
+    }
+}
+
+/* Emit insns to copy SRC into DEST converting SRC if necessary.  */
+
+static inline rtx
+emit_partition_copy (rtx dest, rtx src, int unsignedsrcp)
+{
+  rtx seq;
+
+  start_sequence ();
+
+  if (GET_MODE (src) != VOIDmode && GET_MODE (src) != GET_MODE (dest))
+    src = convert_to_mode (GET_MODE (dest), src, unsignedsrcp);
+  emit_move_insn (dest, src);
+
+  seq = get_insns ();
+  end_sequence ();
+
+  return seq;
+}
+
+/* Insert a copy instruction from partition SRC to DEST onto edge E.  */
+
+static void
+insert_partition_copy_on_edge (edge e, int dest, int src)
+{
+  rtx seq;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file,
+              "Inserting a partition copy on edge BB%d->BB%d :"
+              "PART.%d = PART.%d",
+              e->src->index,
+              e->dest->index, dest, src);
+      fprintf (dump_file, "\n");
+    }
+
+  gcc_assert (SA.partition_to_pseudo[dest]);
+  gcc_assert (SA.partition_to_pseudo[src]);
+
+  set_location_for_edge (e);
+
+  seq = emit_partition_copy (SA.partition_to_pseudo[dest],
+                            SA.partition_to_pseudo[src],
+                            TYPE_UNSIGNED (TREE_TYPE (
+                              partition_to_var (SA.map, src))));
+
+  insert_insn_on_edge (seq, e);
 }
 
+/* Insert a copy instruction from expression SRC to partition DEST
+   onto edge E.  */
+
+static void
+insert_value_copy_on_edge (edge e, int dest, tree src)
+{
+  rtx seq, x;
+  enum machine_mode mode;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file,
+              "Inserting a value copy on edge BB%d->BB%d : PART.%d = ",
+              e->src->index,
+              e->dest->index, dest);
+      print_generic_expr (dump_file, src, TDF_SLIM);
+      fprintf (dump_file, "\n");
+    }
+
+  gcc_assert (SA.partition_to_pseudo[dest]);
+
+  set_location_for_edge (e);
+
+  start_sequence ();
+  mode = GET_MODE (SA.partition_to_pseudo[dest]);
+  x = expand_expr (src, SA.partition_to_pseudo[dest], mode, EXPAND_NORMAL);
+  if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode)
+    x = convert_to_mode (mode, x, TYPE_UNSIGNED (TREE_TYPE (src)));
+  if (CONSTANT_P (x) && GET_MODE (x) == VOIDmode
+      && mode != TYPE_MODE (TREE_TYPE (src)))
+    x = convert_modes (mode, TYPE_MODE (TREE_TYPE (src)),
+                         x, TYPE_UNSIGNED (TREE_TYPE (src)));
+  if (x != SA.partition_to_pseudo[dest])
+    emit_move_insn (SA.partition_to_pseudo[dest], x);
+  seq = get_insns ();
+  end_sequence ();
+
+  insert_insn_on_edge (seq, e);
+}
 
-/* This helper function fill insert a copy from a constant or variable SRC to 
-   variable DEST on edge E.  */
+/* Insert a copy instruction from RTL expression SRC to partition DEST
+   onto edge E.  */
 
 static void
-insert_copy_on_edge (edge e, tree dest, tree src)
+insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp)
 {
-  tree copy;
+  rtx seq;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file,
+              "Inserting a temp copy on edge BB%d->BB%d : PART.%d = ",
+              e->src->index,
+              e->dest->index, dest);
+      print_simple_rtl (dump_file, src);
+      fprintf (dump_file, "\n");
+    }
+
+  gcc_assert (SA.partition_to_pseudo[dest]);
+  set_location_for_edge (e);
+
+  seq = emit_partition_copy (SA.partition_to_pseudo[dest],
+                            src,
+                            unsignedsrcp);
 
-  copy = build (MODIFY_EXPR, TREE_TYPE (dest), dest, src);
-  set_is_used (dest);
+  insert_insn_on_edge (seq, e);
+}
 
-  if (TREE_CODE (src) == ADDR_EXPR)
-    src = TREE_OPERAND (src, 0);
-  if (TREE_CODE (src) == VAR_DECL || TREE_CODE (src) == PARM_DECL)
-    set_is_used (src);
+/* Insert a copy instruction from partition SRC to RTL lvalue DEST
+   onto edge E.  */
 
+static void
+insert_part_to_rtx_on_edge (edge e, rtx dest, int src)
+{
+  rtx seq;
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file,
-              "Inserting a copy on edge BB%d->BB%d :",
+              "Inserting a temp copy on edge BB%d->BB%d : ",
               e->src->index,
               e->dest->index);
-      print_generic_expr (dump_file, copy, dump_flags);
-      fprintf (dump_file, "\n");
+      print_simple_rtl (dump_file, dest);
+      fprintf (dump_file, "= PART.%d\n", src);
     }
 
-  bsi_insert_on_edge (e, copy);
+  gcc_assert (SA.partition_to_pseudo[src]);
+  set_location_for_edge (e);
+
+  seq = emit_partition_copy (dest,
+                            SA.partition_to_pseudo[src],
+                            TYPE_UNSIGNED (TREE_TYPE (
+                              partition_to_var (SA.map, src))));
+
+  insert_insn_on_edge (seq, e);
 }
 
 
@@ -203,10 +279,11 @@ new_elim_graph (int size)
 {
   elim_graph g = (elim_graph) xmalloc (sizeof (struct _elim_graph));
 
-  VARRAY_TREE_INIT (g->nodes, 30, "Elimination Node List");
-  VARRAY_TREE_INIT (g->const_copies, 20, "Elimination Constant Copies");
-  VARRAY_INT_INIT (g->edge_list, 20, "Elimination Edge List");
-  VARRAY_INT_INIT (g->stack, 30, " Elimination Stack");
+  g->nodes = VEC_alloc (int, heap, 30);
+  g->const_dests = VEC_alloc (int, heap, 20);
+  g->const_copies = VEC_alloc (tree, heap, 20);
+  g->edge_list = VEC_alloc (int, heap, 20);
+  g->stack = VEC_alloc (int, heap, 30);
   
   g->visited = sbitmap_alloc (size);
 
@@ -219,8 +296,8 @@ new_elim_graph (int size)
 static inline void
 clear_elim_graph (elim_graph g)
 {
-  VARRAY_POP_ALL (g->nodes);
-  VARRAY_POP_ALL (g->edge_list);
+  VEC_truncate (int, g->nodes, 0);
+  VEC_truncate (int, g->edge_list, 0);
 }
 
 
@@ -230,6 +307,11 @@ static inline void
 delete_elim_graph (elim_graph g)
 {
   sbitmap_free (g->visited);
+  VEC_free (int, heap, g->stack);
+  VEC_free (int, heap, g->edge_list);
+  VEC_free (tree, heap, g->const_copies);
+  VEC_free (int, heap, g->const_dests);
+  VEC_free (int, heap, g->nodes);
   free (g);
 }
 
@@ -239,20 +321,22 @@ delete_elim_graph (elim_graph g)
 static inline int
 elim_graph_size (elim_graph g)
 {
-  return VARRAY_ACTIVE_SIZE (g->nodes);
+  return VEC_length (int, g->nodes);
 }
 
 
 /* Add NODE to graph G, if it doesn't exist already.  */
 
 static inline void 
-elim_graph_add_node (elim_graph g, tree node)
+elim_graph_add_node (elim_graph g, int node)
 {
   int x;
-  for (x = 0; x < elim_graph_size (g); x++)
-    if (VARRAY_TREE (g->nodes, x) == node)
+  int t;
+
+  for (x = 0; VEC_iterate (int, g->nodes, x, t); x++)
+    if (t == node)
       return;
-  VARRAY_PUSH_TREE (g->nodes, node);
+  VEC_safe_push (int, heap, g->nodes, node);
 }
 
 
@@ -261,8 +345,8 @@ elim_graph_add_node (elim_graph g, tree node)
 static inline void
 elim_graph_add_edge (elim_graph g, int pred, int succ)
 {
-  VARRAY_PUSH_INT (g->edge_list, pred);
-  VARRAY_PUSH_INT (g->edge_list, succ);
+  VEC_safe_push (int, heap, g->edge_list, pred);
+  VEC_safe_push (int, heap, g->edge_list, succ);
 }
 
 
@@ -274,12 +358,12 @@ elim_graph_remove_succ_edge (elim_graph g, int node)
 {
   int y;
   unsigned x;
-  for (x = 0; x < VARRAY_ACTIVE_SIZE (g->edge_list); x += 2)
-    if (VARRAY_INT (g->edge_list, x) == node)
+  for (x = 0; x < VEC_length (int, g->edge_list); x += 2)
+    if (VEC_index (int, g->edge_list, x) == node)
       {
-        VARRAY_INT (g->edge_list, x) = -1;
-       y = VARRAY_INT (g->edge_list, x + 1);
-       VARRAY_INT (g->edge_list, x + 1) = -1;
+        VEC_replace (int, g->edge_list, x, -1);
+       y = VEC_index (int, g->edge_list, x + 1);
+       VEC_replace (int, g->edge_list, x + 1, -1);
        return y;
       }
   return -1;
@@ -294,12 +378,12 @@ elim_graph_remove_succ_edge (elim_graph g, int node)
 do {                                                                   \
   unsigned x_;                                                         \
   int y_;                                                              \
-  for (x_ = 0; x_ < VARRAY_ACTIVE_SIZE ((GRAPH)->edge_list); x_ += 2)  \
+  for (x_ = 0; x_ < VEC_length (int, (GRAPH)->edge_list); x_ += 2)     \
     {                                                                  \
-      y_ = VARRAY_INT ((GRAPH)->edge_list, x_);                                \
+      y_ = VEC_index (int, (GRAPH)->edge_list, x_);                    \
       if (y_ != (NODE))                                                        \
         continue;                                                      \
-      (VAR) = VARRAY_INT ((GRAPH)->edge_list, x_ + 1);                 \
+      (VAR) = VEC_index (int, (GRAPH)->edge_list, x_ + 1);             \
       CODE;                                                            \
     }                                                                  \
 } while (0)
@@ -313,12 +397,12 @@ do {                                                                      \
 do {                                                                   \
   unsigned x_;                                                         \
   int y_;                                                              \
-  for (x_ = 0; x_ < VARRAY_ACTIVE_SIZE ((GRAPH)->edge_list); x_ += 2)  \
+  for (x_ = 0; x_ < VEC_length (int, (GRAPH)->edge_list); x_ += 2)     \
     {                                                                  \
-      y_ = VARRAY_INT ((GRAPH)->edge_list, x_ + 1);                    \
+      y_ = VEC_index (int, (GRAPH)->edge_list, x_ + 1);                        \
       if (y_ != (NODE))                                                        \
         continue;                                                      \
-      (VAR) = VARRAY_INT ((GRAPH)->edge_list, x_);                     \
+      (VAR) = VEC_index (int, (GRAPH)->edge_list, x_);                 \
       CODE;                                                            \
     }                                                                  \
 } while (0)
@@ -327,43 +411,34 @@ do {                                                                      \
 /* Add T to elimination graph G.  */
 
 static inline void
-eliminate_name (elim_graph g, tree T)
+eliminate_name (elim_graph g, int T)
 {
   elim_graph_add_node (g, T);
 }
 
 
-/* Build elimination graph G for basic block BB on incoming PHI edge I.  */
+/* Build elimination graph G for basic block BB on incoming PHI edge
+   G->e.  */
 
 static void
-eliminate_build (elim_graph g, basic_block B, int i)
+eliminate_build (elim_graph g)
 {
-  tree phi;
-  tree T0, Ti;
+  tree Ti;
   int p0, pi;
+  gimple_stmt_iterator gsi;
 
   clear_elim_graph (g);
   
-  for (phi = phi_nodes (B); phi; phi = PHI_CHAIN (phi))
+  for (gsi = gsi_start_phis (g->e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      T0 = var_to_partition_to_var (g->map, PHI_RESULT (phi));
-      
+      gimple phi = gsi_stmt (gsi);
+
+      p0 = var_to_partition (g->map, gimple_phi_result (phi));
       /* Ignore results which are not in partitions.  */
-      if (T0 == NULL_TREE)
+      if (p0 == NO_PARTITION)
        continue;
 
-      if (PHI_ARG_EDGE (phi, i) == g->e)
-       Ti = PHI_ARG_DEF (phi, i);
-      else
-        {
-         /* On rare occasions, a PHI node may not have the arguments
-            in the same order as all of the other PHI nodes. If they don't 
-            match, find the appropriate index here.  */
-         pi = phi_arg_from_edge (phi, g->e);
-         if (pi == -1)
-           abort();
-         Ti = PHI_ARG_DEF (phi, pi);
-       }
+      Ti = PHI_ARG_DEF (phi, g->e->dest_idx);
 
       /* If this argument is a constant, or a SSA_NAME which is being
         left in SSA form, just queue a copy to be emitted on this
@@ -374,18 +449,16 @@ eliminate_build (elim_graph g, basic_block B, int i)
         {
          /* Save constant copies until all other copies have been emitted
             on this edge.  */
-         VARRAY_PUSH_TREE (g->const_copies, T0);
-         VARRAY_PUSH_TREE (g->const_copies, Ti);
+         VEC_safe_push (int, heap, g->const_dests, p0);
+         VEC_safe_push (tree, heap, g->const_copies, Ti);
        }
       else
         {
-         Ti = var_to_partition_to_var (g->map, Ti);
-         if (T0 != Ti)
+         pi = var_to_partition (g->map, Ti);
+         if (p0 != pi)
            {
-             eliminate_name (g, T0);
-             eliminate_name (g, Ti);
-             p0 = var_to_partition (g->map, T0);
-             pi = var_to_partition (g->map, Ti);
+             eliminate_name (g, p0);
+             eliminate_name (g, pi);
              elim_graph_add_edge (g, p0, pi);
            }
        }
@@ -405,7 +478,7 @@ elim_forward (elim_graph g, int T)
       if (!TEST_BIT (g->visited, S))
         elim_forward (g, S);
     });
-  VARRAY_PUSH_INT (g->stack, T);
+  VEC_safe_push (int, heap, g->stack, T);
 }
 
 
@@ -435,32 +508,49 @@ elim_backward (elim_graph g, int T)
       if (!TEST_BIT (g->visited, P))
         {
          elim_backward (g, P);
-         insert_copy_on_edge (g->e, 
-                              partition_to_var (g->map, P), 
-                              partition_to_var (g->map, T));
+         insert_partition_copy_on_edge (g->e, P, T);
        }
     });
 }
 
+/* Allocate a new pseudo register usable for storing values sitting
+   in NAME (a decl or SSA name), i.e. with matching mode and attributes.  */
+
+static rtx
+get_temp_reg (tree name)
+{
+  tree var = TREE_CODE (name) == SSA_NAME ? SSA_NAME_VAR (name) : name;
+  tree type = TREE_TYPE (var);
+  int unsignedp = TYPE_UNSIGNED (type);
+  enum machine_mode reg_mode
+    = promote_mode (type, DECL_MODE (var), &unsignedp, 0);
+  rtx x = gen_reg_rtx (reg_mode);
+  if (POINTER_TYPE_P (type))
+    mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (var))));
+  return x;
+}
+
 /* Insert required copies for T in graph G.  Check for a strongly connected 
    region, and create a temporary to break the cycle if one is found.  */
 
 static void 
 elim_create (elim_graph g, int T)
 {
-  tree U;
   int P, S;
 
   if (elim_unvisited_predecessor (g, T))
     {
-      U = create_temp (partition_to_var (g->map, T));
-      insert_copy_on_edge (g->e, U, partition_to_var (g->map, T));
+      tree var = partition_to_var (g->map, T);
+      rtx U = get_temp_reg (var);
+      int unsignedsrcp = TYPE_UNSIGNED (TREE_TYPE (var));
+
+      insert_part_to_rtx_on_edge (g->e, U, T);
       FOR_EACH_ELIM_GRAPH_PRED (g, T, P, 
        {
          if (!TEST_BIT (g->visited, P))
            {
              elim_backward (g, P);
-             insert_copy_on_edge (g->e, partition_to_var (g->map, P), U);
+             insert_rtx_to_part_on_edge (g->e, P, U, unsignedsrcp);
            }
        });
     }
@@ -470,1754 +560,493 @@ elim_create (elim_graph g, int T)
       if (S != -1)
        {
          SET_BIT (g->visited, T);
-         insert_copy_on_edge (g->e, 
-                              partition_to_var (g->map, T), 
-                              partition_to_var (g->map, S));
+         insert_partition_copy_on_edge (g->e, T, S);
        }
     }
-  
 }
 
-/* Eliminate all the phi nodes on edge E in graph G. I is the usual PHI
-   index that edge E's values are found on.  */
+
+/* Eliminate all the phi nodes on edge E in graph G.  */
 
 static void
-eliminate_phi (edge e, int i, elim_graph g)
+eliminate_phi (edge e, elim_graph g)
 {
-  int num_nodes = 0;
   int x;
-  basic_block B = e->dest;
 
-#if defined ENABLE_CHECKING
-  if (i == -1)
-    abort ();
-  if (VARRAY_ACTIVE_SIZE (g->const_copies) != 0)
-    abort ();
-#endif
+  gcc_assert (VEC_length (tree, g->const_copies) == 0);
 
-  /* Abnormal edges already have everything coalesced, or the coalescer
-     would have aborted.  */
+  /* Abnormal edges already have everything coalesced.  */
   if (e->flags & EDGE_ABNORMAL)
     return;
 
-  num_nodes = num_var_partitions (g->map);
   g->e = e;
 
-  eliminate_build (g, B, i);
+  eliminate_build (g);
 
   if (elim_graph_size (g) != 0)
     {
+      int part;
+
       sbitmap_zero (g->visited);
-      VARRAY_POP_ALL (g->stack);
+      VEC_truncate (int, g->stack, 0);
 
-      for (x = 0; x < elim_graph_size (g); x++)
+      for (x = 0; VEC_iterate (int, g->nodes, x, part); x++)
         {
-         tree var = VARRAY_TREE (g->nodes, x);
-         int p = var_to_partition (g->map, var);
-         if (!TEST_BIT (g->visited, p))
-           elim_forward (g, p);
+         if (!TEST_BIT (g->visited, part))
+           elim_forward (g, part);
        }
        
       sbitmap_zero (g->visited);
-      while (VARRAY_ACTIVE_SIZE (g->stack) > 0)
+      while (VEC_length (int, g->stack) > 0)
        {
-         x = VARRAY_TOP_INT (g->stack);
-         VARRAY_POP (g->stack);
+         x = VEC_pop (int, g->stack);
          if (!TEST_BIT (g->visited, x))
            elim_create (g, x);
        }
     }
 
   /* If there are any pending constant copies, issue them now.  */
-  while (VARRAY_ACTIVE_SIZE (g->const_copies) > 0)
+  while (VEC_length (tree, g->const_copies) > 0)
     {
-      tree src, dest;
-      src = VARRAY_TOP_TREE (g->const_copies);
-      VARRAY_POP (g->const_copies);
-      dest = VARRAY_TOP_TREE (g->const_copies);
-      VARRAY_POP (g->const_copies);
-      insert_copy_on_edge (e, dest, src);
+      int dest;
+      tree src;
+      src = VEC_pop (tree, g->const_copies);
+      dest = VEC_pop (int, g->const_dests);
+      insert_value_copy_on_edge (e, dest, src);
     }
 }
 
 
-/* Shortcut routine to print messages to file F of the form:
-   "STR1 EXPR1 STR2 EXPR2 STR3."  */
+/* Remove each argument from PHI.  If an arg was the last use of an SSA_NAME, 
+   check to see if this allows another PHI node to be removed.  */
 
 static void
-print_exprs (FILE *f, const char *str1, tree expr1, const char *str2,
-            tree expr2, const char *str3)
+remove_gimple_phi_args (gimple phi)
 {
-  fprintf (f, "%s", str1);
-  print_generic_expr (f, expr1, TDF_SLIM);
-  fprintf (f, "%s", str2);
-  print_generic_expr (f, expr2, TDF_SLIM);
-  fprintf (f, "%s", str3);
-}
-
-
-/* Shortcut routine to print abnormal edge messages to file F of the form:
-   "STR1 EXPR1 STR2 EXPR2 across edge E.  */
-
-static void
-print_exprs_edge (FILE *f, edge e, const char *str1, tree expr1, 
-                 const char *str2, tree expr2)
-{
-  print_exprs (f, str1, expr1, str2, expr2, " across an abnormal edge");
-  fprintf (f, " from BB%d->BB%d\n", e->src->index,
-              e->dest->index);
-}
-
-
-/* Coalesce partitions in MAP which are live across abnormal edges in GRAPH.
-   RV is the root variable groupings of the partitions in MAP.  Since code 
-   cannot be inserted on these edges, failure to coalesce something across
-   an abnormal edge is an error.  */
-
-static void
-coalesce_abnormal_edges (var_map map, conflict_graph graph, root_var_p rv)
-{
-  basic_block bb;
-  edge e;
-  tree phi, var, tmp;
-  int x, y;
-
-  /* Code cannot be inserted on abnormal edges. Look for all abnormal 
-     edges, and coalesce any PHI results with their arguments across 
-     that edge.  */
+  use_operand_p arg_p;
+  ssa_op_iter iter;
 
-  FOR_EACH_BB (bb)
-    for (e = bb->succ; e; e = e->succ_next)
-      if (e->dest != EXIT_BLOCK_PTR && e->flags & EDGE_ABNORMAL)
-       for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
-         {
-           /* Visit each PHI on the destination side of this abnormal
-              edge, and attempt to coalesce the argument with the result.  */
-           var = PHI_RESULT (phi);
-           x = var_to_partition (map, var);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Removing Dead PHI definition: ");
+      print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
+    }
 
-           /* Ignore results which are not relevant.  */
-           if (x == NO_PARTITION)
-             continue;
+  FOR_EACH_PHI_ARG (arg_p, phi, iter, SSA_OP_USE)
+    {
+      tree arg = USE_FROM_PTR (arg_p);
+      if (TREE_CODE (arg) == SSA_NAME)
+        {
+         /* Remove the reference to the existing argument.  */
+         SET_USE (arg_p, NULL_TREE);
+         if (has_zero_uses (arg))
+           {
+             gimple stmt;
+             gimple_stmt_iterator gsi;
 
-           y = phi_arg_from_edge (phi, e);
-           if (y == -1)
-             abort ();
+             stmt = SSA_NAME_DEF_STMT (arg);
 
-           tmp = PHI_ARG_DEF (phi, y);
-           if (!phi_ssa_name_p (tmp))
-             {
-               print_exprs_edge (stderr, e,
-                                 "\nConstant argument in PHI. Can't insert :",
-                                 var, " = ", tmp);
-               abort ();
-             }
-           y = var_to_partition (map, tmp);
-           if (x == NO_PARTITION || y == NO_PARTITION)
-             abort ();
-           if (root_var_find (rv, x) != root_var_find (rv, y))
-             {
-               print_exprs_edge (stderr, e, "\nDifferent root vars: ",
-                                 root_var (rv, root_var_find (rv, x)), 
-                                 " and ", 
-                                 root_var (rv, root_var_find (rv, y)));
-               abort ();
-             }
+             /* Also remove the def if it is a PHI node.  */
+             if (gimple_code (stmt) == GIMPLE_PHI)
+               {
+                 remove_gimple_phi_args (stmt);
+                 gsi = gsi_for_stmt (stmt);
+                 remove_phi_node (&gsi, true);
+               }
 
-           if (x != y)
-             {
-               if (!conflict_graph_conflict_p (graph, x, y))
-                 {
-                   /* Now map the partitions back to their real variables.  */
-                   var = partition_to_var (map, x);
-                   tmp = partition_to_var (map, y);
-                   if (dump_file 
-                       && (dump_flags & TDF_DETAILS))
-                     {
-                       print_exprs_edge (dump_file, e, 
-                                         "ABNORMAL: Coalescing ",
-                                         var, " and ", tmp);
-                     }
-                   if (var_union (map, var, tmp) == NO_PARTITION)
-                     {
-                       print_exprs_edge (stderr, e, "\nUnable to coalesce", 
-                                         partition_to_var (map, x), " and ", 
-                                         partition_to_var (map, y));
-                       abort ();
-                     }
-                   conflict_graph_merge_regs (graph, x, y);
-                 }
-               else
-                 {
-                   print_exprs_edge (stderr, e, "\n Conflict ", 
-                                     partition_to_var (map, x),
-                                     " and ", partition_to_var (map, y));
-                   abort ();
-                 }
-             }
-         }
+           }
+       }
+    }
 }
 
+/* Remove any PHI node which is a virtual PHI, or a PHI with no uses.  */
 
-/* Reduce the number of live ranges in MAP.  Live range information is 
-   returned if FLAGS indicates that we are combining temporaries, otherwise 
-   NULL is returned.  The only partitions which are associated with actual 
-   variables at this point are those which are forced to be coalesced for 
-   various reason. (live on entry, live across abnormal edges, etc.).  */
-
-static tree_live_info_p
-coalesce_ssa_name (var_map map, int flags)
+static void
+eliminate_useless_phis (void)
 {
-  int num, x, i;
-  sbitmap live;
-  tree var, phi;
-  root_var_p rv;
-  tree_live_info_p liveinfo;
-  var_ann_t ann;
-  conflict_graph graph;
   basic_block bb;
-  coalesce_list_p cl = NULL;
-
-  if (num_var_partitions (map) <= 1)
-    return NULL;
-
-  /* If no preference given, use cheap coalescing of all partitions.  */
-  if ((flags & (SSANORM_COALESCE_PARTITIONS | SSANORM_USE_COALESCE_LIST)) == 0)
-    flags |= SSANORM_COALESCE_PARTITIONS;
-  
-  liveinfo = calculate_live_on_entry (map);
-  calculate_live_on_exit (liveinfo);
-  rv = root_var_init (map);
-
-  /* Remove single element variable from the list.  */
-  root_var_compact (rv);
+  gimple_stmt_iterator gsi;
+  tree result;
 
-  if (flags & SSANORM_USE_COALESCE_LIST)
+  FOR_EACH_BB (bb)
     {
-      cl = create_coalesce_list (map);
-      
-      /* Add all potential copies via PHI arguments to the list.  */
-      FOR_EACH_BB (bb)
-       {
-         for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); )
+        {
+         gimple phi = gsi_stmt (gsi);
+         result = gimple_phi_result (phi);
+         if (!is_gimple_reg (SSA_NAME_VAR (result)))
            {
-             tree res = PHI_RESULT (phi);
-             int p = var_to_partition (map, res);
-             if (p == NO_PARTITION)
-               continue;
-             for (x = 0; x < PHI_NUM_ARGS (phi); x++)
-               {
-                 tree arg = PHI_ARG_DEF (phi, x);
-                 int p2;
-
-                 if (TREE_CODE (arg) != SSA_NAME)
-                   continue;
-                 if (SSA_NAME_VAR (res) != SSA_NAME_VAR (arg))
-                   continue;
-                 p2 = var_to_partition (map, PHI_ARG_DEF (phi, x));
-                 if (p2 != NO_PARTITION)
-                   add_coalesce (cl, p, p2, 1);
+#ifdef ENABLE_CHECKING
+             size_t i;
+             /* There should be no arguments which are not virtual, or the
+                results will be incorrect.  */
+             for (i = 0; i < gimple_phi_num_args (phi); i++)
+               {
+                 tree arg = PHI_ARG_DEF (phi, i);
+                 if (TREE_CODE (arg) == SSA_NAME 
+                     && is_gimple_reg (SSA_NAME_VAR (arg)))
+                   {
+                     fprintf (stderr, "Argument of PHI is not virtual (");
+                     print_generic_expr (stderr, arg, TDF_SLIM);
+                     fprintf (stderr, "), but the result is :");
+                     print_gimple_stmt (stderr, phi, 0, TDF_SLIM);
+                     internal_error ("SSA corruption");
+                   }
                }
+#endif
+             remove_phi_node (&gsi, true);
            }
-       }
-
-      /* Coalesce all the result decls together.  */
-      var = NULL_TREE;
-      i = 0;
-      for (x = 0; x < num_var_partitions (map); x++)
-       {
-         tree p = partition_to_var (map, x);
-         if (TREE_CODE (SSA_NAME_VAR(p)) == RESULT_DECL)
+          else
            {
-             if (var == NULL_TREE)
-               {
-                 var = p;
-                 i = x;
+             /* Also remove real PHIs with no uses.  */
+             if (has_zero_uses (result))
+               {
+                 remove_gimple_phi_args (phi);
+                 remove_phi_node (&gsi, true);
                }
              else
-               add_coalesce (cl, i, x, 1);
+               gsi_next (&gsi);
            }
        }
     }
+}
 
-  /* Build a conflict graph.  */
-  graph = build_tree_conflict_graph (liveinfo, rv, cl);
-
-  if (cl)
-    {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Before sorting:\n");
-         dump_coalesce_list (dump_file, cl);
-       }
-
-      sort_coalesce_list (cl);
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "\nAfter sorting:\n");
-         dump_coalesce_list (dump_file, cl);
-       }
-    }
-
-  /* Put the single element variables back in.  */
-  root_var_decompact (rv);
-
-  /* First, coalesce all live on entry variables to their root variable. 
-     This will ensure the first use is coming from the correct location.  */
-
-  live = sbitmap_alloc (num_var_partitions (map));
-  sbitmap_zero (live);
-
-  /* Set 'live' vector to indicate live on entry partitions.  */
-  num = num_var_partitions (map);
-  for (x = 0 ; x < num; x++)
-    {
-      var = partition_to_var (map, x);
-      if (default_def (SSA_NAME_VAR (var)) == var)
-       SET_BIT (live, x);
-    }
 
-  if ((flags & SSANORM_COMBINE_TEMPS) == 0)
-    {
-      delete_tree_live_info (liveinfo);
-      liveinfo = NULL;
-    }
+/* This function will rewrite the current program using the variable mapping
+   found in MAP.  If the replacement vector VALUES is provided, any 
+   occurrences of partitions with non-null entries in the vector will be 
+   replaced with the expression in the vector instead of its mapped 
+   variable.  */
 
-  /* Assign root variable as partition representative for each live on entry
-     partition.  */
-  EXECUTE_IF_SET_IN_SBITMAP (live, 0, x, 
+static void
+rewrite_trees (var_map map ATTRIBUTE_UNUSED)
+{
+#ifdef ENABLE_CHECKING
+  basic_block bb;
+  /* Search for PHIs where the destination has no partition, but one
+     or more arguments has a partition.  This should not happen and can
+     create incorrect code.  */
+  FOR_EACH_BB (bb)
     {
-      var = root_var (rv, root_var_find (rv, x));
-      ann = var_ann (var);
-      /* If these aren't already coalesced...  */
-      if (partition_to_var (map, x) != var)
+      gimple_stmt_iterator gsi;
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         if (ann->out_of_ssa_tag)
+         gimple phi = gsi_stmt (gsi);
+         tree T0 = var_to_partition_to_var (map, gimple_phi_result (phi));
+         if (T0 == NULL_TREE)
            {
-             /* This root variable has already been assigned to another
-                partition which is not coalesced with this one.  */
-             abort ();
-           }
+             size_t i;
+             for (i = 0; i < gimple_phi_num_args (phi); i++)
+               {
+                 tree arg = PHI_ARG_DEF (phi, i);
 
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             print_exprs (dump_file, "Must coalesce ", 
-                          partition_to_var (map, x),
-                          " with the root variable ", var, ".\n");
+                 if (TREE_CODE (arg) == SSA_NAME
+                     && var_to_partition (map, arg) != NO_PARTITION)
+                   {
+                     fprintf (stderr, "Argument of PHI is in a partition :(");
+                     print_generic_expr (stderr, arg, TDF_SLIM);
+                     fprintf (stderr, "), but the result is not :");
+                     print_gimple_stmt (stderr, phi, 0, TDF_SLIM);
+                     internal_error ("SSA corruption");
+                   }
+               }
            }
-
-         change_partition_var (map, var, x);
        }
-    });
-
-  sbitmap_free (live);
+    }
+#endif
+}
 
-  /* Coalesce partitions live across abnormal edges.  */
-  coalesce_abnormal_edges (map, graph, rv);
+/* Given the out-of-ssa info object SA (with prepared partitions)
+   eliminate all phi nodes in all basic blocks.  Afterwards no
+   basic block will have phi nodes anymore and there are possibly
+   some RTL instructions inserted on edges.  */
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    dump_var_map (dump_file, map);
+void
+expand_phi_nodes (struct ssaexpand *sa)
+{
+  basic_block bb;
+  elim_graph g = new_elim_graph (sa->map->num_partitions);
+  g->map = sa->map;
 
-  /* Coalesce partitions.  */
-  if (flags & SSANORM_USE_COALESCE_LIST)
-    coalesce_tpa_members (rv, graph, map, cl, 
-                         ((dump_flags & TDF_DETAILS) ? dump_file 
-                                                          : NULL));
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR, next_bb)
+    if (!gimple_seq_empty_p (phi_nodes (bb)))
+      {
+       edge e;
+       edge_iterator ei;
+       FOR_EACH_EDGE (e, ei, bb->preds)
+         eliminate_phi (e, g);
+       set_phi_nodes (bb, NULL);
+       /* We can't redirect EH edges in RTL land, so we need to do this
+          here.  Redirection happens only when splitting is necessary,
+          which it is only for critical edges, normally.  For EH edges
+          it might also be necessary when the successor has more than
+          one predecessor.  In that case the edge is either required to
+          be fallthru (which EH edges aren't), or the predecessor needs
+          to end with a jump (which again, isn't the case with EH edges).
+          Hence, split all EH edges on which we inserted instructions
+          and whose successor has multiple predecessors.  */
+       for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
+         {
+           if (e->insns.r && (e->flags & EDGE_EH)
+               && !single_pred_p (e->dest))
+             {
+               rtx insns = e->insns.r;
+               basic_block bb;
+               e->insns.r = NULL_RTX;
+               bb = split_edge (e);
+               single_pred_edge (bb)->insns.r = insns;
+             }
+           else
+             ei_next (&ei);
+         }
+      }
 
-  
-  if (flags & SSANORM_COALESCE_PARTITIONS)
-    coalesce_tpa_members (rv, graph, map, NULL, 
-                         ((dump_flags & TDF_DETAILS) ? dump_file 
-                                                          : NULL));
-  if (cl)
-    delete_coalesce_list (cl);
-  root_var_delete (rv);
-  conflict_graph_delete (graph);
-
-  return liveinfo;
+  delete_elim_graph (g);
 }
 
 
-/* Take the ssa-name var_map MAP, and assign real variables to each 
-   partition.  */
+/* Remove the ssa-names in the current function and translate them into normal
+   compiler variables.  PERFORM_TER is true if Temporary Expression Replacement
+   should also be used.  */
 
 static void
-assign_vars (var_map map)
+remove_ssa_form (bool perform_ter, struct ssaexpand *sa)
 {
-  int x, i, num, rep;
-  tree t, var;
-  var_ann_t ann;
-  root_var_p rv;
+  bitmap values = NULL;
+  var_map map;
+  unsigned i;
 
-  rv = root_var_init (map);
-  if (!rv) 
-    return;
+  map = coalesce_ssa_name ();
 
-  /* Coalescing may already have forced some partitions to their root 
-     variable. Find these and tag them.  */
+  /* Return to viewing the variable list as just all reference variables after
+     coalescing has been performed.  */
+  partition_view_normal (map, false);
 
-  num = num_var_partitions (map);
-  for (x = 0; x < num; x++)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      var = partition_to_var (map, x);
-      if (TREE_CODE (var) != SSA_NAME)
-       {
-         /* Coalescing will already have verified that more than one
-            partition doesn't have the same root variable. Simply marked
-            the variable as assigned.  */
-         ann = var_ann (var);
-         ann->out_of_ssa_tag = 1;
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "partition %d has variable ", x);
-             print_generic_expr (dump_file, var, TDF_SLIM);
-             fprintf (dump_file, " assigned to it.\n");
-           }
-
-       }
+      fprintf (dump_file, "After Coalescing:\n");
+      dump_var_map (dump_file, map);
     }
 
-  num = root_var_num (rv);
-  for (x = 0; x < num; x++)
+  if (perform_ter)
     {
-      var = root_var (rv, x);
-      ann = var_ann (var);
-      for (i = root_var_first_partition (rv, x);
-          i != ROOT_VAR_NONE;
-          i = root_var_next_partition (rv, i))
-       {
-         t = partition_to_var (map, i);
-
-         if (t == var || TREE_CODE (t) != SSA_NAME)
-           continue;
-
-         rep = var_to_partition (map, t);
-         
-         if (!ann->out_of_ssa_tag)
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               print_exprs (dump_file, "", t, "  --> ", var, "\n");
-             change_partition_var (map, var, rep);
-             continue;
-           }
-
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           print_exprs (dump_file, "", t, " not coalesced with ", var, 
-                        "");
+      values = find_replaceable_exprs (map);
+      if (values && dump_file && (dump_flags & TDF_DETAILS))
+       dump_replaceable_exprs (dump_file, values);
+    }
 
-         var = create_temp (t);
-         change_partition_var (map, var, rep);
-         ann = var_ann (var);
+  rewrite_trees (map);
 
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, " -->  New temp:  '");
-             print_generic_expr (dump_file, var, TDF_SLIM);
-             fprintf (dump_file, "'\n");
-           }
+  sa->map = map;
+  sa->values = values;
+  sa->partition_has_default_def = BITMAP_ALLOC (NULL);
+  for (i = 1; i < num_ssa_names; i++)
+    {
+      tree t = ssa_name (i);
+      if (t && SSA_NAME_IS_DEFAULT_DEF (t))
+       {
+         int p = var_to_partition (map, t);
+         if (p != NO_PARTITION)
+           bitmap_set_bit (sa->partition_has_default_def, p);
        }
     }
-
-  root_var_delete (rv);
 }
 
 
-/* Replace use operand P with whatever variable it has been rewritten to based 
-   on the partitions in MAP.  EXPR is an optional expression vector over SSA 
-   versions which is used to replace P with an expression instead of a variable.
-   If the stmt is changed, return true.  */ 
+/* If not already done so for basic block BB, assign increasing uids
+   to each of its instructions.  */
 
-static inline bool
-replace_use_variable (var_map map, use_operand_p p, tree *expr)
+static void
+maybe_renumber_stmts_bb (basic_block bb)
 {
-  tree new_var;
-  tree var = USE_FROM_PTR (p);
-
-  /* Check if we are replacing this variable with an expression.  */
-  if (expr)
-    {
-      int version = SSA_NAME_VERSION (var);
-      if (expr[version])
-        {
-         tree new_expr = TREE_OPERAND (expr[version], 1);
-         SET_USE (p, new_expr);
-         /* Clear the stmt's RHS, or GC might bite us.  */
-         TREE_OPERAND (expr[version], 1) = NULL_TREE;
-         return true;
-       }
-    }
-
-  new_var = var_to_partition_to_var (map, var);
-  if (new_var)
+  unsigned i = 0;
+  gimple_stmt_iterator gsi;
+  
+  if (!bb->aux)
+    return;
+  bb->aux = NULL;
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      SET_USE (p, new_var);
-      set_is_used (new_var);
-      return true;
+      gimple stmt = gsi_stmt (gsi);
+      gimple_set_uid (stmt, i);
+      i++;
     }
-  return false;
 }
 
 
-/* Replace def operand DEF_P with whatever variable it has been rewritten to 
-   based on the partitions in MAP.  EXPR is an optional expression vector over
-   SSA versions which is used to replace DEF_P with an expression instead of a 
-   variable.  If the stmt is changed, return true.  */ 
+/* Return true if we can determine that the SSA_NAMEs RESULT (a result
+   of a PHI node) and ARG (one of its arguments) conflict.  Return false
+   otherwise, also when we simply aren't sure.  */
 
-static inline bool
-replace_def_variable (var_map map, def_operand_p def_p, tree *expr)
+static bool
+trivially_conflicts_p (basic_block bb, tree result, tree arg)
 {
-  tree new_var;
-  tree var = DEF_FROM_PTR (def_p);
+  use_operand_p use;
+  imm_use_iterator imm_iter;
+  gimple defa = SSA_NAME_DEF_STMT (arg);
 
-  /* Check if we are replacing this variable with an expression.  */
-  if (expr)
-    {
-      int version = SSA_NAME_VERSION (var);
-      if (expr[version])
-        {
-         tree new_expr = TREE_OPERAND (expr[version], 1);
-         SET_DEF (def_p, new_expr);
-         /* Clear the stmt's RHS, or GC might bite us.  */
-         TREE_OPERAND (expr[version], 1) = NULL_TREE;
-         return true;
-       }
-    }
+  /* If ARG isn't defined in the same block it's too complicated for
+     our little mind.  */
+  if (gimple_bb (defa) != bb)
+    return false;
 
-  new_var = var_to_partition_to_var (map, var);
-  if (new_var)
+  FOR_EACH_IMM_USE_FAST (use, imm_iter, result)
     {
-      SET_DEF (def_p, new_var);
-      set_is_used (new_var);
-      return true;
+      gimple use_stmt = USE_STMT (use);
+      /* Now, if there's a use of RESULT that lies outside this basic block,
+        then there surely is a conflict with ARG.  */
+      if (gimple_bb (use_stmt) != bb)
+       return true;
+      if (gimple_code (use_stmt) == GIMPLE_PHI)
+       continue;
+      /* The use now is in a real stmt of BB, so if ARG was defined
+         in a PHI node (like RESULT) both conflict.  */
+      if (gimple_code (defa) == GIMPLE_PHI)
+       return true;
+      maybe_renumber_stmts_bb (bb);
+      /* If the use of RESULT occurs after the definition of ARG,
+         the two conflict too.  */
+      if (gimple_uid (defa) < gimple_uid (use_stmt))
+       return true;
     }
+  
   return false;
 }
 
 
-/* Remove any PHI node which is a virtual PHI.  */
+/* Search every PHI node for arguments associated with backedges which
+   we can trivially determine will need a copy (the argument is either
+   not an SSA_NAME or the argument has a different underlying variable
+   than the PHI result).
+
+   Insert a copy from the PHI argument to a new destination at the
+   end of the block with the backedge to the top of the loop.  Update
+   the PHI argument to reference this new destination.  */
 
 static void
-eliminate_virtual_phis (void)
+insert_backedge_copies (void)
 {
   basic_block bb;
-  tree phi, next;
+  gimple_stmt_iterator gsi;
 
   FOR_EACH_BB (bb)
     {
-      for (phi = phi_nodes (bb); phi; phi = next)
-        {
-         next = PHI_CHAIN (phi);
-         if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
+      /* Mark block as possibly needing calculation of UIDs.  */
+      bb->aux = &bb->aux;
+
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple phi = gsi_stmt (gsi);
+         tree result = gimple_phi_result (phi);
+         tree result_var;
+         size_t i;
+
+         if (!is_gimple_reg (result))
+           continue;
+
+         result_var = SSA_NAME_VAR (result);
+         for (i = 0; i < gimple_phi_num_args (phi); i++)
            {
-#ifdef ENABLE_CHECKING
-             int i;
-             /* There should be no arguments of this PHI which are in
-                the partition list, or we get incorrect results.  */
-             for (i = 0; i < PHI_NUM_ARGS (phi); i++)
-               {
-                 tree arg = PHI_ARG_DEF (phi, i);
-                 if (TREE_CODE (arg) == SSA_NAME 
-                     && is_gimple_reg (SSA_NAME_VAR (arg)))
-                   {
-                     fprintf (stderr, "Argument of PHI is not virtual (");
-                     print_generic_expr (stderr, arg, TDF_SLIM);
-                     fprintf (stderr, "), but the result is :");
-                     print_generic_stmt (stderr, phi, TDF_SLIM);
-                     abort();
-                   }
-               }
-#endif
-             remove_phi_node (phi, NULL_TREE, bb);
-           }
-       }
-    }
-}
-
-
-/* This routine will coalesce variables in MAP of the same type which do not 
-   interfere with each other. LIVEINFO is the live range info for variables
-   of interest.  This will both reduce the memory footprint of the stack, and 
-   allow us to coalesce together local copies of globals and scalarized 
-   component refs.  */
-
-static void
-coalesce_vars (var_map map, tree_live_info_p liveinfo)
-{
-  basic_block bb;
-  type_var_p tv;
-  tree var;
-  int x, p, p2;
-  coalesce_list_p cl;
-  conflict_graph graph;
-
-  cl = create_coalesce_list (map);
-
-  /* Merge all the live on entry vectors for coalesced partitions.  */
-  for (x = 0; x < num_var_partitions (map); x++)
-    {
-      var = partition_to_var (map, x);
-      p = var_to_partition (map, var);
-      if (p != x)
-        live_merge_and_clear (liveinfo, p, x);
-    }
-
-  /* When PHI nodes are turned into copies, the result of each PHI node
-     becomes live on entry to the block. Mark these now.  */
-  FOR_EACH_BB (bb)
-    {
-      tree phi, arg;
-      int p;
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       {
-         p = var_to_partition (map, PHI_RESULT (phi));
-
-         /* Skip virtual PHI nodes.  */
-         if (p == NO_PARTITION)
-           continue;
-
-         make_live_on_entry (liveinfo, bb, p);
-
-         /* Each argument is a potential copy operation. Add any arguments 
-            which are not coalesced to the result to the coalesce list.  */
-         for (x = 0; x < PHI_NUM_ARGS (phi); x++)
-           {
-             arg = PHI_ARG_DEF (phi, x);
-             if (!phi_ssa_name_p (arg))
-               continue;
-             p2 = var_to_partition (map, arg);
-             if (p2 == NO_PARTITION)
-               continue;
-             if (p != p2)
-               add_coalesce (cl, p, p2, 1);
-           }
-       }
-   }
-
-  
-  /* Re-calculate live on exit info.  */
-  calculate_live_on_exit (liveinfo);
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "Live range info for variable memory coalescing.\n");
-      dump_live_info (dump_file, liveinfo, LIVEDUMP_ALL);
-
-      fprintf (dump_file, "Coalesce list from phi nodes:\n");
-      dump_coalesce_list (dump_file, cl);
-    }
-
-
-  tv = type_var_init (map);
-  if (dump_file)
-    type_var_dump (dump_file, tv);
-  type_var_compact (tv);
-  if (dump_file)
-    type_var_dump (dump_file, tv);
-
-  graph = build_tree_conflict_graph (liveinfo, tv, cl);
-
-  type_var_decompact (tv);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "type var list now looks like:n");
-      type_var_dump (dump_file, tv);
-
-      fprintf (dump_file, "Coalesce list after conflict graph build:\n");
-      dump_coalesce_list (dump_file, cl);
-    }
-
-  sort_coalesce_list (cl);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "Coalesce list after sorting:\n");
-      dump_coalesce_list (dump_file, cl);
-    }
-
-  coalesce_tpa_members (tv, graph, map, cl, 
-                       ((dump_flags & TDF_DETAILS) ? dump_file : NULL));
-
-  type_var_delete (tv);
-  delete_coalesce_list (cl);
-}
-
-
-/* Temporary Expression Replacement (TER)
-
-   Replace SSA version variables during out-of-ssa with their defining
-   expression if there is only one use of the variable.
-
-   A pass is made through the function, one block at a time.  No cross block
-   information is tracked.
-
-   Variables which only have one use, and whose defining stmt is considered
-   a replaceable expression (see check_replaceable) are entered into 
-   consideration by adding a list of dependent partitions to the version_info
-   vector for that ssa_name_version.  This information comes from the partition
-   mapping for each USE.  At the same time, the partition_dep_list vector for 
-   these partitions have this version number entered into their lists.
-
-   When the use of a replaceable ssa_variable is encountered, the dependence
-   list in version_info[] is moved to the "pending_dependence" list in case
-   the current expression is also replaceable. (To be determined later in 
-   processing this stmt.) version_info[] for the version is then updated to 
-   point to the defining stmt and the 'replaceable' bit is set.
-
-   Any partition which is defined by a statement 'kills' any expression which
-   is dependent on this partition.  Every ssa version in the partitions' 
-   dependence list is removed from future consideration.
-
-   All virtual references are lumped together.  Any expression which is
-   dependent on any virtual variable (via a VUSE) has a dependence added
-   to the special partition defined by VIRTUAL_PARTITION.
-
-   Whenever a V_MAY_DEF is seen, all expressions dependent this 
-   VIRTUAL_PARTITION are removed from consideration.
-
-   At the end of a basic block, all expression are removed from consideration
-   in preparation for the next block.  
-   
-   The end result is a vector over SSA_NAME_VERSION which is passed back to
-   rewrite_out_of_ssa.  As the SSA variables are being rewritten, instead of
-   replacing the SSA_NAME tree element with the partition it was assigned, 
-   it is replaced with the RHS of the defining expression.  */
-
-
-/* Dependency list element.  This can contain either a partition index or a
-   version number, depending on which list it is in.  */
-
-typedef struct value_expr_d 
-{
-  int value;
-  struct value_expr_d *next;
-} *value_expr_p;
-
-
-/* Temporary Expression Replacement (TER) table information.  */
-
-typedef struct temp_expr_table_d 
-{
-  var_map map;
-  void **version_info;         
-  value_expr_p *partition_dep_list;
-  bitmap replaceable;
-  bool saw_replaceable;
-  int virtual_partition;
-  bitmap partition_in_use;
-  value_expr_p free_list;
-  value_expr_p pending_dependence;
-} *temp_expr_table_p;
-
-/* Used to indicate a dependency on V_MAY_DEFs.  */
-#define VIRTUAL_PARTITION(table)       (table->virtual_partition)
-
-static temp_expr_table_p new_temp_expr_table (var_map);
-static tree *free_temp_expr_table (temp_expr_table_p);
-static inline value_expr_p new_value_expr (temp_expr_table_p);
-static inline void free_value_expr (temp_expr_table_p, value_expr_p);
-static inline value_expr_p find_value_in_list (value_expr_p, int, 
-                                              value_expr_p *);
-static inline void add_value_to_list (temp_expr_table_p, value_expr_p *, int);
-static inline void add_info_to_list (temp_expr_table_p, value_expr_p *, 
-                                    value_expr_p);
-static value_expr_p remove_value_from_list (value_expr_p *, int);
-static void add_dependance (temp_expr_table_p, int, tree);
-static bool check_replaceable (temp_expr_table_p, tree);
-static void finish_expr (temp_expr_table_p, int, bool);
-static void mark_replaceable (temp_expr_table_p, tree);
-static inline void kill_expr (temp_expr_table_p, int, bool);
-static inline void kill_virtual_exprs (temp_expr_table_p, bool);
-static void find_replaceable_in_bb (temp_expr_table_p, basic_block);
-static tree *find_replaceable_exprs (var_map);
-static void dump_replaceable_exprs (FILE *, tree *);
-
-
-/* Create a new TER table for MAP.  */
-
-static temp_expr_table_p
-new_temp_expr_table (var_map map)
-{
-  temp_expr_table_p t;
-
-  t = (temp_expr_table_p) xmalloc (sizeof (struct temp_expr_table_d));
-  t->map = map;
-
-  t->version_info = xcalloc (num_ssa_names + 1, sizeof (void *));
-  t->partition_dep_list = xcalloc (num_var_partitions (map) + 1, 
-                                  sizeof (value_expr_p));
-
-  t->replaceable = BITMAP_XMALLOC ();
-  t->partition_in_use = BITMAP_XMALLOC ();
-
-  t->saw_replaceable = false;
-  t->virtual_partition = num_var_partitions (map);
-  t->free_list = NULL;
-  t->pending_dependence = NULL;
-
-  return t;
-}
-
-
-/* Free TER table T.  If there are valid replacements, return the expression 
-   vector.  */
-
-static tree *
-free_temp_expr_table (temp_expr_table_p t)
-{
-  value_expr_p p;
-  tree *ret = NULL;
-
-#ifdef ENABLE_CHECKING
-  int x;
-  for (x = 0; x <= num_var_partitions (t->map); x++)
-    if (t->partition_dep_list[x] != NULL)
-      abort();
-#endif
-
-  while ((p = t->free_list))
-    {
-      t->free_list = p->next;
-      free (p);
-    }
-
-  BITMAP_XFREE (t->partition_in_use);
-  BITMAP_XFREE (t->replaceable);
-
-  free (t->partition_dep_list);
-  if (t->saw_replaceable)
-    ret = (tree *)t->version_info;
-  else
-    free (t->version_info);
-  
-  free (t);
-  return ret;
-}
-
-
-/* Allocate a new value list node. Take it from the free list in TABLE if 
-   possible.  */
-
-static inline value_expr_p
-new_value_expr (temp_expr_table_p table)
-{
-  value_expr_p p;
-  if (table->free_list)
-    {
-      p = table->free_list;
-      table->free_list = p->next;
-    }
-  else
-    p = (value_expr_p) xmalloc (sizeof (struct value_expr_d));
-
-  return p;
-}
-
-
-/* Add value list node P to the free list in TABLE.  */
-
-static inline void
-free_value_expr (temp_expr_table_p table, value_expr_p p)
-{
-  p->next = table->free_list;
-  table->free_list = p;
-}
-
-
-/* Find VALUE if its in LIST.  Return a pointer to the list object if found,  
-   else return NULL.  If LAST_PTR is provided, it will point to the previous 
-   item upon return, or NULL if this is the first item in the list.  */
-
-static inline value_expr_p
-find_value_in_list (value_expr_p list, int value, value_expr_p *last_ptr)
-{
-  value_expr_p curr;
-  value_expr_p last = NULL;
-
-  for (curr = list; curr; last = curr, curr = curr->next)
-    {
-      if (curr->value == value)
-        break;
-    }
-  if (last_ptr)
-    *last_ptr = last;
-  return curr;
-}
-
-
-/* Add VALUE to LIST, if it isn't already present.  TAB is the expression 
-   table */
-
-static inline void
-add_value_to_list (temp_expr_table_p tab, value_expr_p *list, int value)
-{
-  value_expr_p info;
-
-  if (!find_value_in_list (*list, value, NULL))
-    {
-      info = new_value_expr (tab);
-      info->value = value;
-      info->next = *list;
-      *list = info;
-    }
-}
-
-
-/* Add value node INFO if it's value isn't already in LIST.  Free INFO if
-   it is already in the list. TAB is the expression table.  */
-
-static inline void
-add_info_to_list (temp_expr_table_p tab, value_expr_p *list, value_expr_p info)
-{
-  if (find_value_in_list (*list, info->value, NULL))
-    free_value_expr (tab, info);
-  else
-    {
-      info->next = *list;
-      *list = info;
-    }
-}
-
-
-/* Look for VALUE in LIST.  If found, remove it from the list and return it's 
-   pointer.  */
-
-static value_expr_p
-remove_value_from_list (value_expr_p *list, int value)
-{
-  value_expr_p info, last;
-
-  info = find_value_in_list (*list, value, &last);
-  if (!info)
-    return NULL;
-  if (!last)
-    *list = info->next;
-  else
-    last->next = info->next;
-  return info;
-}
-
-
-/* Add a dependency between the def of ssa VERSION and VAR.  If VAR is 
-   replaceable by an expression, add a dependence each of the elements of the 
-   expression.  These are contained in the pending list.  TAB is the
-   expression table.  */
-
-static void
-add_dependance (temp_expr_table_p tab, int version, tree var)
-{
-  int i, x;
-  value_expr_p info;
-
-  i = SSA_NAME_VERSION (var);
-  if (bitmap_bit_p (tab->replaceable, i))
-    {
-      /* This variable is being substituted, so use whatever dependences
-         were queued up when we marked this as replaceable earlier.  */
-      while ((info = tab->pending_dependence))
-        {
-         tab->pending_dependence = info->next;
-         /* Get the partition this variable was dependent on. Reuse this
-            object to represent the current  expression instead.  */
-         x = info->value;
-         info->value = version;
-         add_info_to_list (tab, &(tab->partition_dep_list[x]), info);
-          add_value_to_list (tab, 
-                            (value_expr_p *)&(tab->version_info[version]), x);
-         bitmap_set_bit (tab->partition_in_use, x);
-       }
-    }
-  else
-    {
-      i = var_to_partition (tab->map, var);
-#ifdef ENABLE_CHECKING
-      if (i== NO_PARTITION)
-       abort ();
-#endif
-      add_value_to_list (tab, &(tab->partition_dep_list[i]), version);
-      add_value_to_list (tab, 
-                        (value_expr_p *)&(tab->version_info[version]), i);
-      bitmap_set_bit (tab->partition_in_use, i);
-    }
-}
-
-
-/* Check if expression STMT is suitable for replacement in table TAB.  If so, 
-   create an expression entry.  Return true if this stmt is replaceable.  */
-
-static bool
-check_replaceable (temp_expr_table_p tab, tree stmt)
-{
-  stmt_ann_t ann;
-  vuse_optype vuseops;
-  def_optype defs;
-  use_optype uses;
-  tree var, def;
-  int num_use_ops, version, i;
-  var_map map = tab->map;
-
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
-    return false;
-  
-  ann = stmt_ann (stmt);
-  defs = DEF_OPS (ann);
-
-  /* Punt if there is more than 1 def, or more than 1 use.  */
-  if (NUM_DEFS (defs) != 1)
-    return false;
-  def = DEF_OP (defs, 0);
-  if (version_ref_count (map, def) != 1)
-    return false;
-
-  /* Assignments to variables assigned to hard registers are not
-     replaceable.  */
-  if (DECL_HARD_REGISTER (SSA_NAME_VAR (def)))
-    return false;
-
-  /* There must be no V_MAY_DEFS.  */
-  if (NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) != 0)
-    return false;
-
-  /* There must be no V_MUST_DEFS.  */
-  if (NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) != 0)
-    return false;
-
-  /* Float expressions must go through memory if float-store is on.  */
-  if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1))))
-    return false;
-
-  uses = USE_OPS (ann);
-  num_use_ops = NUM_USES (uses);
-  vuseops = VUSE_OPS (ann);
-
-  /* Any expression which has no virtual operands and no real operands
-     should have been propagated if it's possible to do anything with them. 
-     If this happens here, it probably exists that way for a reason, so we 
-     won't touch it.   An example is:
-         b_4 = &tab
-     There are no virtual uses nor any real uses, so we just leave this 
-     alone to be safe.  */
-
-  if (num_use_ops == 0 && NUM_VUSES (vuseops) == 0)
-    return false;
-
-  version = SSA_NAME_VERSION (def);
-
-  /* Add this expression to the dependency list for each use partition.  */
-  for (i = 0; i < num_use_ops; i++)
-    {
-      var = USE_OP (uses, i);
-      add_dependance (tab, version, var);
-    }
-
-  /* If there are VUSES, add a dependence on virtual defs.  */
-  if (NUM_VUSES (vuseops) != 0)
-    {
-      add_value_to_list (tab, (value_expr_p *)&(tab->version_info[version]), 
-                        VIRTUAL_PARTITION (tab));
-      add_value_to_list (tab, 
-                        &(tab->partition_dep_list[VIRTUAL_PARTITION (tab)]), 
-                        version);
-      bitmap_set_bit (tab->partition_in_use, VIRTUAL_PARTITION (tab));
-    }
-
-  return true;
-}
-
-
-/* This function will remove the expression for VERSION from replacement 
-   consideration.n table TAB  If 'replace' is true, it is marked as 
-   replaceable, otherwise not.  */
-
-static void
-finish_expr (temp_expr_table_p tab, int version, bool replace)
-{
-  value_expr_p info, tmp;
-  int partition;
-
-  /* Remove this expression from its dependent lists.  The partition dependence
-     list is retained and transfered later to whomever uses this version.  */
-  for (info = (value_expr_p) tab->version_info[version]; info; info = tmp)
-    {
-      partition = info->value;
-#ifdef ENABLE_CHECKING
-      if (tab->partition_dep_list[partition] == NULL)
-        abort ();
-#endif
-      tmp = remove_value_from_list (&(tab->partition_dep_list[partition]), 
-                                   version);
-#ifdef ENABLE_CHECKING
-      if (!tmp)
-        abort ();
-#endif
-      free_value_expr (tab, tmp);
-      /* Only clear the bit when the dependency list is emptied via 
-         a replacement. Otherwise kill_expr will take care of it.  */
-      if (!(tab->partition_dep_list[partition]) && replace)
-        bitmap_clear_bit (tab->partition_in_use, partition);
-      tmp = info->next;
-      if (!replace)
-        free_value_expr (tab, info);
-    }
-
-  if (replace)
-    {
-      tab->saw_replaceable = true;
-      bitmap_set_bit (tab->replaceable, version);
-    }
-  else
-    {
-#ifdef ENABLE_CHECKING
-      if (bitmap_bit_p (tab->replaceable, version))
-       abort ();
-#endif
-      tab->version_info[version] = NULL;
-    }
-}
-
-
-/* Mark the expression associated with VAR as replaceable, and enter
-   the defining stmt into the version_info table TAB.  */
-
-static void
-mark_replaceable (temp_expr_table_p tab, tree var)
-{
-  value_expr_p info;
-  int version = SSA_NAME_VERSION (var);
-  finish_expr (tab, version, true);
-
-  /* Move the dependence list to the pending list.  */
-  if (tab->version_info[version])
-    {
-      info = (value_expr_p) tab->version_info[version]; 
-      for ( ; info->next; info = info->next)
-       continue;
-      info->next = tab->pending_dependence;
-      tab->pending_dependence = (value_expr_p)tab->version_info[version];
-    }
-
-  tab->version_info[version] = SSA_NAME_DEF_STMT (var);
-}
-
-
-/* This function marks any expression in TAB which is dependent on PARTITION
-   as NOT replaceable.  CLEAR_BIT is used to determine whether partition_in_use
-   should have its bit cleared.  Since this routine can be called within an
-   EXECUTE_IF_SET_IN_BITMAP, the bit can't always be cleared.  */
-
-static inline void
-kill_expr (temp_expr_table_p tab, int partition, bool clear_bit)
-{
-  value_expr_p ptr;
-
-  /* Mark every active expr dependent on this var as not replaceable.  */
-  while ((ptr = tab->partition_dep_list[partition]) != NULL)
-    finish_expr (tab, ptr->value, false);
-
-  if (clear_bit)
-    bitmap_clear_bit (tab->partition_in_use, partition);
-}
-
-
-/* This function kills all expressions in TAB which are dependent on virtual 
-   DEFs.  CLEAR_BIT determines whether partition_in_use gets cleared.  */
-
-static inline void
-kill_virtual_exprs (temp_expr_table_p tab, bool clear_bit)
-{
-  kill_expr (tab, VIRTUAL_PARTITION (tab), clear_bit);
-}
-
-
-/* This function processes basic block BB, and looks for variables which can
-   be replaced by their expressions.  Results are stored in TAB.  */
-
-static void
-find_replaceable_in_bb (temp_expr_table_p tab, basic_block bb)
-{
-  block_stmt_iterator bsi;
-  tree stmt, def;
-  stmt_ann_t ann;
-  int partition, num, i;
-  use_optype uses;
-  def_optype defs;
-  var_map map = tab->map;
-  value_expr_p p;
-
-  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-    {
-      stmt = bsi_stmt (bsi);
-      ann = stmt_ann (stmt);
-
-      /* Determine if this stmt finishes an existing expression.  */
-      uses = USE_OPS (ann);
-      num = NUM_USES (uses);
-      for (i = 0; i < num; i++)
-       {
-         def = USE_OP (uses, i);
-         if (tab->version_info[SSA_NAME_VERSION (def)])
-           {
-             /* Mark expression as replaceable unless stmt is volatile.  */
-             if (!ann->has_volatile_ops)
-               mark_replaceable (tab, def);
-             else
-               finish_expr (tab, SSA_NAME_VERSION (def), false);
-           }
-       }
-      
-      /* Next, see if this stmt kills off an active expression.  */
-      defs = DEF_OPS (ann);
-      num = NUM_DEFS (defs);
-      for (i = 0; i < num; i++)
-       {
-         def = DEF_OP (defs, i);
-         partition = var_to_partition (map, def);
-         if (partition != NO_PARTITION && tab->partition_dep_list[partition])
-           kill_expr (tab, partition, true);
-       }
-
-      /* Now see if we are creating a new expression or not.  */
-      if (!ann->has_volatile_ops)
-       check_replaceable (tab, stmt);
-
-      /* Free any unused dependency lists.  */
-      while ((p = tab->pending_dependence))
-       {
-         tab->pending_dependence = p->next;
-         free_value_expr (tab, p);
-       }
-
-      /* A V_MAY_DEF kills any expression using a virtual operand.  */
-      if (NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) > 0)
-        kill_virtual_exprs (tab, true);
-       
-      /* A V_MUST_DEF kills any expression using a virtual operand.  */
-      if (NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) > 0)
-        kill_virtual_exprs (tab, true);
-    }
-}
-
-
-/* This function is the driver routine for replacement of temporary expressions
-   in the SSA->normal phase, operating on MAP.  If there are replaceable 
-   expressions, a table is returned which maps SSA versions to the 
-   expressions they should be replaced with.  A NULL_TREE indicates no 
-   replacement should take place.  If there are no replacements at all, 
-   NULL is returned by the function, otherwise an expression vector indexed
-   by SSA_NAME version numbers.  */
-
-static tree *
-find_replaceable_exprs (var_map map)
-{
-  basic_block bb;
-  int i;
-  temp_expr_table_p table;
-  tree *ret;
-
-  table = new_temp_expr_table (map);
-  FOR_EACH_BB (bb)
-    {
-      find_replaceable_in_bb (table, bb);
-      EXECUTE_IF_SET_IN_BITMAP ((table->partition_in_use), 0, i,
-        {
-         kill_expr (table, i, false);
-       });
-    }
-
-  ret = free_temp_expr_table (table);
-  return ret;
-}
-
-
-/* Dump TER expression table EXPR to file F.  */
-
-static void
-dump_replaceable_exprs (FILE *f, tree *expr)
-{
-  tree stmt, var;
-  int x;
-  fprintf (f, "\nReplacing Expressions\n");
-  for (x = 0; x < (int)num_ssa_names + 1; x++)
-    if (expr[x])
-      {
-        stmt = expr[x];
-       var = DEF_OP (STMT_DEF_OPS (stmt), 0);
-       print_generic_expr (f, var, TDF_SLIM);
-       fprintf (f, " replace with --> ");
-       print_generic_expr (f, TREE_OPERAND (stmt, 1), TDF_SLIM);
-       fprintf (f, "\n");
-      }
-  fprintf (f, "\n");
-}
-
-
-/* Helper function for discover_nonconstant_array_refs. 
-   Look for ARRAY_REF nodes with non-constant indexes and mark them
-   addressable.  */
-
-static tree
-discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees,
-                                  void *data ATTRIBUTE_UNUSED)
-{
-  tree t = *tp;
-
-  if (TYPE_P (t) || DECL_P (t))
-    *walk_subtrees = 0;
-  else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
-    {
-      while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
-             && is_gimple_min_invariant (TREE_OPERAND (t, 1))
-             && (!TREE_OPERAND (t, 2)
-                 || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
-            || (TREE_CODE (t) == COMPONENT_REF
-                && (!TREE_OPERAND (t,2)
-                    || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
-            || TREE_CODE (t) == BIT_FIELD_REF
-            || TREE_CODE (t) == REALPART_EXPR
-            || TREE_CODE (t) == IMAGPART_EXPR
-            || TREE_CODE (t) == VIEW_CONVERT_EXPR
-            || TREE_CODE (t) == NOP_EXPR
-            || TREE_CODE (t) == CONVERT_EXPR)
-       t = TREE_OPERAND (t, 0);
-
-      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
-       {
-         t = get_base_address (t);
-         if (t && DECL_P (t))
-           TREE_ADDRESSABLE (t) = 1;
-       }
-
-      *walk_subtrees = 0;
-    }
-
-  return NULL_TREE;
-}
-
-
-/* RTL expansion is not able to compile array references with variable
-   offsets for arrays stored in single register.  Discover such
-   expressions and mark variables as addressable to avoid this
-   scenario.  */
-
-static void
-discover_nonconstant_array_refs (void)
-{
-  basic_block bb;
-  block_stmt_iterator bsi;
-
-  FOR_EACH_BB (bb)
-    {
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       walk_tree (bsi_stmt_ptr (bsi), discover_nonconstant_array_refs_r,
-                  NULL , NULL);
-    }
-}
-
-
-/* This function will rewrite the current program using the variable mapping
-   found in MAP.  If the replacement vector VALUES is provided, any 
-   occurrences of partitions with non-null entries in the vector will be 
-   replaced with the expression in the vector instead of its mapped 
-   variable.  */
-
-static void
-rewrite_trees (var_map map, tree *values)
-{
-  elim_graph g;
-  basic_block bb;
-  block_stmt_iterator si;
-  edge e;
-  tree phi;
-  bool changed;
-#ifdef ENABLE_CHECKING
-  /* Search for PHIs where the destination has no partition, but one
-     or more arguments has a partition.  This should not happen and can
-     create incorrect code.  */
-  FOR_EACH_BB (bb)
-    {
-      tree phi;
-
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       {
-         tree T0 = var_to_partition_to_var (map, PHI_RESULT (phi));
-      
-         if (T0 == NULL_TREE)
-           {
-             int i;
-
-             for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+             tree arg = gimple_phi_arg_def (phi, i);
+             edge e = gimple_phi_arg_edge (phi, i);
+
+             /* If the argument is not an SSA_NAME, then we will need a 
+                constant initialization.  If the argument is an SSA_NAME with
+                a different underlying variable then a copy statement will be 
+                needed.  */
+             if ((e->flags & EDGE_DFS_BACK)
+                 && (TREE_CODE (arg) != SSA_NAME
+                     || SSA_NAME_VAR (arg) != result_var
+                     || trivially_conflicts_p (bb, result, arg)))
                {
-                 tree arg = PHI_ARG_DEF (phi, i);
-
-                 if (TREE_CODE (arg) == SSA_NAME
-                     && var_to_partition (map, arg) != NO_PARTITION)
+                 tree name;
+                 gimple stmt, last = NULL;
+                 gimple_stmt_iterator gsi2;
+
+                 gsi2 = gsi_last_bb (gimple_phi_arg_edge (phi, i)->src);
+                 if (!gsi_end_p (gsi2))
+                   last = gsi_stmt (gsi2);
+
+                 /* In theory the only way we ought to get back to the
+                    start of a loop should be with a COND_EXPR or GOTO_EXPR.
+                    However, better safe than sorry. 
+                    If the block ends with a control statement or
+                    something that might throw, then we have to
+                    insert this assignment before the last
+                    statement.  Else insert it after the last statement.  */
+                 if (last && stmt_ends_bb_p (last))
                    {
-                     fprintf (stderr, "Argument of PHI is in a partition :(");
-                     print_generic_expr (stderr, arg, TDF_SLIM);
-                     fprintf (stderr, "), but the result is not :");
-                     print_generic_stmt (stderr, phi, TDF_SLIM);
-                     abort();
+                     /* If the last statement in the block is the definition
+                        site of the PHI argument, then we can't insert
+                        anything after it.  */
+                     if (TREE_CODE (arg) == SSA_NAME
+                         && SSA_NAME_DEF_STMT (arg) == last)
+                       continue;
                    }
-               }
-           }
-       }
-    }
-#endif
-
-  /* Replace PHI nodes with any required copies.  */
-  g = new_elim_graph (map->num_partitions);
-  g->map = map;
-  FOR_EACH_BB (bb)
-    {
-      for (si = bsi_start (bb); !bsi_end_p (si); )
-       {
-         size_t i, num_uses, num_defs;
-         use_optype uses;
-         def_optype defs;
-         tree stmt = bsi_stmt (si);
-         use_operand_p use_p;
-         int remove = 0, is_copy = 0;
-         stmt_ann_t ann;
-
-         get_stmt_operands (stmt);
-         ann = stmt_ann (stmt);
-         changed = false;
-
-         if (TREE_CODE (stmt) == MODIFY_EXPR 
-             && (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME))
-           is_copy = 1;
-
-         uses = USE_OPS (ann);
-         num_uses = NUM_USES (uses);
-
-         for (i = 0; i < num_uses; i++)
-           {
-             use_p = USE_OP_PTR (uses, i);
-             if (replace_use_variable (map, use_p, values))
-               changed = true;
-           }
-
-         defs = DEF_OPS (ann);
-         num_defs = NUM_DEFS (defs);
 
-         /* Mark this stmt for removal if it is the list of replaceable 
-            expressions.  */
-         if (values && num_defs == 1)
-           {
-             tree def = DEF_OP (defs, 0);
-             tree val;
-             val = values[SSA_NAME_VERSION (def)];
-             if (val)
-               remove = 1;
-           }
-         if (!remove)
-           {
-             for (i = 0; i < num_defs; i++)
-               {
-                 def_operand_p def_p = DEF_OP_PTR (defs, i);
-
-                 if (replace_def_variable (map, def_p, NULL))
-                   changed = true;
-
-                 /* If both SSA_NAMEs coalesce to the same variable,
-                    mark the now redundant copy for removal.  */
-                 if (is_copy
-                     && num_uses == 1
-                     && (DEF_FROM_PTR (def_p) == USE_OP (uses, 0)))
-                   remove = 1;
+                 /* Create a new instance of the underlying variable of the 
+                    PHI result.  */
+                 stmt = gimple_build_assign (result_var,
+                                             gimple_phi_arg_def (phi, i));
+                 name = make_ssa_name (result_var, stmt);
+                 gimple_assign_set_lhs (stmt, name);
+
+                 /* Insert the new statement into the block and update
+                    the PHI node.  */
+                 if (last && stmt_ends_bb_p (last))
+                   gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
+                 else
+                   gsi_insert_after (&gsi2, stmt, GSI_NEW_STMT);
+                 SET_PHI_ARG_DEF (phi, i, name);
                }
-             if (changed)
-               modify_stmt (stmt);
            }
-
-         /* Remove any stmts marked for removal.  */
-         if (remove)
-           bsi_remove (&si);
-         else
-           bsi_next (&si);
-       }
-
-      phi = phi_nodes (bb);
-      if (phi)
-        {
-         for (e = bb->pred; e; e = e->pred_next)
-           eliminate_phi (e, phi_arg_from_edge (phi, e), g);
-       }
-    }
-
-  delete_elim_graph (g);
-
-  /* If any copies were inserted on edges, actually insert them now.  */
-  bsi_commit_edge_inserts (NULL);
-}
-
-
-/* Remove the variables specified in MAP from SSA form.  Any debug information
-   is sent to DUMP.  FLAGS indicate what options should be used.  */
-
-void
-remove_ssa_form (FILE *dump, var_map map, int flags)
-{
-  tree_live_info_p liveinfo;
-  basic_block bb;
-  tree phi, next;
-  FILE *save;
-  tree *values = NULL;
-
-  save = dump_file;
-  dump_file = dump;
-
-  /* If we are not combining temps, don't calculate live ranges for variables
-     with only one SSA version.  */
-  if ((flags & SSANORM_COMBINE_TEMPS) == 0)
-    compact_var_map (map, VARMAP_NO_SINGLE_DEFS);
-  else
-    compact_var_map (map, VARMAP_NORMAL);
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    dump_var_map (dump_file, map);
-
-  liveinfo = coalesce_ssa_name (map, flags);
-
-  /* Make sure even single occurrence variables are in the list now.  */
-  if ((flags & SSANORM_COMBINE_TEMPS) == 0)
-    compact_var_map (map, VARMAP_NORMAL);
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "After Coalescing:\n");
-      dump_var_map (dump_file, map);
-    }
-
-  if (flags & SSANORM_PERFORM_TER)
-    {
-      values = find_replaceable_exprs (map);
-      if (values && dump_file && (dump_flags & TDF_DETAILS))
-       dump_replaceable_exprs (dump_file, values);
-    }
-
-  /* Assign real variables to the partitions now.  */
-  assign_vars (map);
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "After Root variable replacement:\n");
-      dump_var_map (dump_file, map);
-    }
-
-  if ((flags & SSANORM_COMBINE_TEMPS) && liveinfo)
-    {
-      coalesce_vars (map, liveinfo);
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "After variable memory coalescing:\n");
-         dump_var_map (dump_file, map);
        }
-    }
-  
-  if (liveinfo)
-    delete_tree_live_info (liveinfo);
 
-  rewrite_trees (map, values);
-
-  if (values)
-    free (values);
-
-  /* Remove phi nodes which have been translated back to real variables.  */
-  FOR_EACH_BB (bb)
-    {
-      for (phi = phi_nodes (bb); phi; phi = next)
-       {
-         next = PHI_CHAIN (phi);
-         if ((flags & SSANORM_REMOVE_ALL_PHIS) 
-             || var_to_partition (map, PHI_RESULT (phi)) != NO_PARTITION)
-           remove_phi_node (phi, NULL_TREE, bb);
-       }
+      /* Unmark this block again.  */
+      bb->aux = NULL;
     }
-
-  dump_file = save;
 }
 
-
-/* Take a subset of the variables VARS in the current function out of SSA
-   form.  */
+/* Free all memory associated with going out of SSA form.  SA is
+   the outof-SSA info object.  */
 
 void
-rewrite_vars_out_of_ssa (bitmap vars)
+finish_out_of_ssa (struct ssaexpand *sa)
 {
-  if (bitmap_first_set_bit (vars) >= 0)
-    {
-      var_map map;
-      basic_block bb;
-      tree phi;
-      int i;
-      int ssa_flags;
-
-      /* Search for PHIs in which one of the PHI arguments is marked for
-        translation out of SSA form, but for which the PHI result is not
-        marked for translation out of SSA form.
-
-        Our per-variable out of SSA translation can not handle that case;
-        however we can easily handle it here by creating a new instance
-        of the PHI result's underlying variable and initializing it to
-        the offending PHI argument on the edge associated with the
-        PHI argument.  We then change the PHI argument to use our new
-        instead of the PHI's underlying variable.
-
-        You might think we could register partitions for the out-of-ssa
-        translation here and avoid a second walk of the PHI nodes.  No
-        such luck since the size of the var map will change if we have
-        to manually take variables out of SSA form here.  */
-      FOR_EACH_BB (bb)
-       {
-         for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-           {
-             tree result = SSA_NAME_VAR (PHI_RESULT (phi));
-
-             /* If the definition is marked for renaming, then we need
-                to do nothing more for this PHI node.  */
-             if (bitmap_bit_p (vars, var_ann (result)->uid))
-               continue;
-
-             /* Look at all the arguments and see if any of them are
-                marked for renaming.  If so, we need to handle them
-                specially.  */
-             for (i = 0; i < PHI_NUM_ARGS (phi); i++)
-               {
-                 tree arg = PHI_ARG_DEF (phi, i);
-
-                 /* If the argument is not an SSA_NAME, then we can ignore
-                    this argument.  */
-                 if (TREE_CODE (arg) != SSA_NAME)
-                   continue;
-
-                 /* If this argument is marked for renaming, then we need
-                    to undo the copy propagation so that we can take
-                    the argument out of SSA form without taking the
-                    result out of SSA form.  */
-                 arg = SSA_NAME_VAR (arg);
-                 if (bitmap_bit_p (vars, var_ann (arg)->uid))
-                   {
-                     tree new_name, copy;
-
-                     /* Get a new SSA_NAME for the copy, it is based on
-                        the result, not the argument!   We use the PHI
-                        as the definition since we haven't created the
-                        definition statement yet.  */
-                     new_name = make_ssa_name (result, phi);
-
-                     /* Now create the copy statement.  */
-                     copy = build (MODIFY_EXPR, TREE_TYPE (arg),
-                                   new_name, PHI_ARG_DEF (phi, i));
-
-                     /* Now update SSA_NAME_DEF_STMT to point to the
-                        newly created statement.  */
-                     SSA_NAME_DEF_STMT (new_name) = copy;
-
-                     /* Now make the argument reference our new SSA_NAME.  */
-                     SET_PHI_ARG_DEF (phi, i, new_name);
-
-                     /* Queue the statement for insertion.  */
-                     bsi_insert_on_edge (PHI_ARG_EDGE (phi, i), copy);
-                     modify_stmt (copy);
-                   }
-               }
-           }
-       }
-
-      /* If any copies were inserted on edges, actually insert them now.  */
-      bsi_commit_edge_inserts (NULL);
-                                                                                
-      /* Now register partitions for all instances of the variables we
-        are taking out of SSA form.  */
-      map = init_var_map (num_ssa_names + 1);
-      register_ssa_partitions_for_vars (vars, map);
-
-      /* Now that we have all the partitions registered, translate the
-        appropriate variables out of SSA form.  */
-      ssa_flags = SSANORM_COALESCE_PARTITIONS;
-      if (flag_tree_combine_temps)
-       ssa_flags |= SSANORM_COMBINE_TEMPS;
-      remove_ssa_form (dump_file, map, ssa_flags);
-
-      /* And finally, reset the out_of_ssa flag for each of the vars
-        we just took out of SSA form.  */
-      EXECUTE_IF_SET_IN_BITMAP (vars, 0, i,
-       {
-         var_ann (referenced_var (i))->out_of_ssa_tag = 0;
-       });
-
-     /* Free the map as we are done with it.  */
-     delete_var_map (map);
-
-    }
+  free (sa->partition_to_pseudo);
+  if (sa->values)
+    BITMAP_FREE (sa->values);
+  delete_var_map (sa->map);
+  BITMAP_FREE (sa->partition_has_default_def);
+  memset (sa, 0, sizeof *sa);
 }
 
-
-/* Take the current function out of SSA form, as described in
+/* Take the current function out of SSA form, translating PHIs as described in
    R. Morgan, ``Building an Optimizing Compiler'',
    Butterworth-Heinemann, Boston, MA, 1998. pp 176-186.  */
 
-static void
-rewrite_out_of_ssa (void)
+unsigned int
+rewrite_out_of_ssa (struct ssaexpand *sa)
 {
-  var_map map;
-  int var_flags = 0;
-  int ssa_flags = (SSANORM_REMOVE_ALL_PHIS | SSANORM_USE_COALESCE_LIST);
-
-  if (!flag_tree_live_range_split)
-    ssa_flags |= SSANORM_COALESCE_PARTITIONS;
-    
-  eliminate_virtual_phis ();
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    dump_tree_cfg (dump_file, dump_flags & ~TDF_DETAILS);
+  /* If elimination of a PHI requires inserting a copy on a backedge,
+     then we will have to split the backedge which has numerous
+     undesirable performance effects.
 
-  /* We cannot allow unssa to un-gimplify trees before we instrument them.  */
-  if (flag_tree_ter && !flag_mudflap)
-    var_flags = SSA_VAR_MAP_REF_COUNT;
+     A significant number of such cases can be handled here by inserting
+     copies into the loop itself.  */
+  insert_backedge_copies ();
 
-  map = create_ssa_var_map (var_flags);
 
-  if (flag_tree_combine_temps)
-    ssa_flags |= SSANORM_COMBINE_TEMPS;
-  if (flag_tree_ter && !flag_mudflap)
-    ssa_flags |= SSANORM_PERFORM_TER;
-
-  remove_ssa_form (dump_file, map, ssa_flags);
+  /* Eliminate PHIs which are of no use, such as virtual or dead phis.  */
+  eliminate_useless_phis ();
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    dump_tree_cfg (dump_file, dump_flags & ~TDF_DETAILS);
+    gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
 
-  /* Do some cleanups which reduce the amount of data the
-     tree->rtl expanders deal with.  */
-  cfg_remove_useless_stmts ();
+  remove_ssa_form (flag_tree_ter, sa);
 
-  /* Flush out flow graph and SSA data.  */
-  delete_var_map (map);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
 
-  /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE.  */
-  discover_nonconstant_array_refs ();
+  return 0;
 }
-
-
-/* Define the parameters of the out of SSA pass.  */
-
-struct tree_opt_pass pass_del_ssa = 
-{
-  "optimized",                         /* name */
-  NULL,                                        /* gate */
-  rewrite_out_of_ssa,                  /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_SSA_TO_NORMAL,               /* tv_id */
-  PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
-  0,                                   /* properties_provided */
-  /* ??? If TER is enabled, we also kill gimple.  */
-  PROP_ssa,                            /* properties_destroyed */
-  TODO_verify_ssa | TODO_verify_flow
-    | TODO_verify_stmts,               /* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect    /* todo_flags_finish */
-};