OSDN Git Service

2009-10-19 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-coalesce.c
index 6bf530f..5841aa0 100644 (file)
@@ -1,12 +1,13 @@
 /* Coalesce SSA_NAMES together for the out-of-ssa pass.
-   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+   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,9 +16,8 @@ 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, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -48,6 +48,7 @@ typedef struct coalesce_pair
   int second_element;
   int cost;
 } * coalesce_pair_p;
+typedef const struct coalesce_pair *const_coalesce_pair_p;
 
 typedef struct cost_one_pair_d
 {
@@ -70,11 +71,10 @@ typedef struct coalesce_list_d
 #define MUST_COALESCE_COST     INT_MAX
 
 
-/* Return cost of execution of copy instruction with FREQUENCY
-   possibly on CRITICAL edge and in HOT basic block.  */
+/* Return cost of execution of copy instruction with FREQUENCY.  */
 
 static inline int
-coalesce_cost (int frequency, bool hot, bool critical)
+coalesce_cost (int frequency, bool optimize_for_size)
 {
   /* Base costs on BB frequencies bounded by 1.  */
   int cost = frequency;
@@ -82,16 +82,9 @@ coalesce_cost (int frequency, bool hot, bool critical)
   if (!cost)
     cost = 1;
 
-  if (optimize_size)
+  if (optimize_for_size)
     cost = 1;
-  else
-    /* It is more important to coalesce in HOT blocks.  */
-    if (hot)
-      cost *= 2;
 
-  /* Inserting copy on critical edge costs more than inserting it elsewhere.  */
-  if (critical)
-    cost *= 2;
   return cost;
 }
 
@@ -101,7 +94,7 @@ coalesce_cost (int frequency, bool hot, bool critical)
 static inline int 
 coalesce_cost_bb (basic_block bb)
 {
-  return coalesce_cost (bb->frequency, maybe_hot_bb_p (bb), false);
+  return coalesce_cost (bb->frequency, optimize_bb_for_size_p (bb));
 }
 
 
@@ -110,12 +103,38 @@ coalesce_cost_bb (basic_block bb)
 static inline int 
 coalesce_cost_edge (edge e)
 {
+  int mult = 1;
+
+  /* Inserting copy on critical edge costs more than inserting it elsewhere.  */
+  if (EDGE_CRITICAL_P (e))
+    mult = 2;
   if (e->flags & EDGE_ABNORMAL)
     return MUST_COALESCE_COST;
+  if (e->flags & EDGE_EH)
+    {
+      edge e2;
+      edge_iterator ei;
+      FOR_EACH_EDGE (e2, ei, e->dest->preds)
+       if (e2 != e)
+         {
+           /* Putting code on EH edge that leads to BB
+              with multiple predecestors imply splitting of
+              edge too.  */
+           if (mult < 2)
+             mult = 2;
+           /* If there are multiple EH predecestors, we
+              also copy EH regions and produce separate
+              landing pad.  This is expensive.  */
+           if (e2->flags & EDGE_EH)
+             {
+               mult = 5;
+               break;
+             }
+         }
+    }
 
   return coalesce_cost (EDGE_FREQUENCY (e), 
-                       maybe_hot_bb_p (e->src), 
-                       EDGE_CRITICAL_P (e));
+                       optimize_edge_for_size_p (e)) * mult;
 }
 
 
@@ -174,21 +193,21 @@ pop_best_coalesce (coalesce_list_p cl, int *p1, int *p2)
 static unsigned int 
 coalesce_pair_map_hash (const void *pair)
 {
-  hashval_t a = (hashval_t)(((coalesce_pair_p)pair)->first_element);
-  hashval_t b = (hashval_t)(((coalesce_pair_p)pair)->second_element);
+  hashval_t a = (hashval_t)(((const_coalesce_pair_p)pair)->first_element);
+  hashval_t b = (hashval_t)(((const_coalesce_pair_p)pair)->second_element);
 
   return COALESCE_HASH_FN (a,b);
 }
 
 
 /* Equality function for coalesce list hash table.  Compare PAIR1 and PAIR2,
-   returning TRUE if the two pairs are equivilent. */
+   returning TRUE if the two pairs are equivalent.  */
 
 static int 
 coalesce_pair_map_eq (const void *pair1, const void *pair2)
 {
-  coalesce_pair_p p1 = (coalesce_pair_p) pair1;
-  coalesce_pair_p p2 = (coalesce_pair_p) pair2;
+  const_coalesce_pair_p const p1 = (const_coalesce_pair_p) pair1;
+  const_coalesce_pair_p const p2 = (const_coalesce_pair_p) pair2;
 
   return (p1->first_element == p2->first_element
          && p1->second_element == p2->second_element);
@@ -260,7 +279,7 @@ find_coalesce_pair (coalesce_list_p cl, int p1, int p2, bool create)
   if (create && !pair)
     {
       gcc_assert (cl->sorted == NULL);
-      pair = xmalloc (sizeof (struct coalesce_pair));
+      pair = XNEW (struct coalesce_pair);
       pair->first_element = p.first_element;
       pair->second_element = p.second_element;
       pair->cost = 0;
@@ -276,7 +295,7 @@ add_cost_one_coalesce (coalesce_list_p cl, int p1, int p2)
 {
   cost_one_pair_p pair;
 
-  pair = xmalloc (sizeof (struct cost_one_pair_d));
+  pair = XNEW (struct cost_one_pair_d);
   pair->first_element = p1;
   pair->second_element = p2;
   pair->next = cl->cost_one_list;
@@ -287,8 +306,7 @@ add_cost_one_coalesce (coalesce_list_p cl, int p1, int p2)
 /* Add a coalesce between P1 and P2 in list CL with a cost of VALUE.  */
 
 static inline void 
-add_coalesce (coalesce_list_p cl, int p1, int p2,
-             int value)
+add_coalesce (coalesce_list_p cl, int p1, int p2, int value)
 {
   coalesce_pair_p node;
 
@@ -298,23 +316,38 @@ add_coalesce (coalesce_list_p cl, int p1, int p2,
 
   node = find_coalesce_pair (cl, p1, p2, true);
 
-  /* Once the value is MUST_COALESCE_COST, leave it that way.  */
-  if (node->cost != MUST_COALESCE_COST)
+  /* Once the value is at least MUST_COALESCE_COST - 1, leave it that way.  */
+  if (node->cost < MUST_COALESCE_COST - 1)
     {
-      if (value == MUST_COALESCE_COST)
-       node->cost = value;
-      else
+      if (value < MUST_COALESCE_COST - 1)
        node->cost += value;
+      else
+       node->cost = value;
     }
 }
 
 
-/* Comparison function to allow qsort to sort P1 and P2 in Ascendiong order.  */
+/* Comparison function to allow qsort to sort P1 and P2 in Ascending order.  */
 
 static int 
 compare_pairs (const void *p1, const void *p2)
 {
-  return (*(coalesce_pair_p *)p1)->cost - (*(coalesce_pair_p *)p2)->cost;
+  const_coalesce_pair_p const *const pp1 = (const_coalesce_pair_p const *) p1;
+  const_coalesce_pair_p const *const pp2 = (const_coalesce_pair_p const *) p2;
+  int result;
+
+  result = (* pp1)->cost - (* pp2)->cost;
+  /* Since qsort does not guarantee stability we use the elements
+     as a secondary key.  This provides us with independence from
+     the host's implementation of the sorting algorithm.  */
+  if (result == 0)
+    {
+      result = (* pp2)->first_element - (* pp1)->first_element;
+      if (result == 0)
+       result = (* pp2)->second_element - (* pp1)->second_element;
+    }
+
+  return result;
 }
 
 
@@ -355,7 +388,7 @@ end_coalesce_pair_p (coalesce_pair_iterator *iter)
 }
 
 
-/* Return the next parttition pair to be visited by ITER.  */
+/* Return the next partition pair to be visited by ITER.  */
 
 static inline coalesce_pair_p
 next_coalesce_pair (coalesce_pair_iterator *iter)
@@ -466,7 +499,7 @@ dump_coalesce_list (FILE *f, coalesce_list_p cl)
 
 
 /* This represents a conflict graph.  Implemented as an array of bitmaps.  
-   A full matrix isused for conflicts rather than just upper triangular form.
+   A full matrix is used for conflicts rather than just upper triangular form.
    this make sit much simpler and faster to perform conflict merges.  */
 
 typedef struct ssa_conflicts_d
@@ -476,7 +509,7 @@ typedef struct ssa_conflicts_d
 } * ssa_conflicts_p;
 
 
-/* Return a empty new conflict graph for SIZE elements.  */
+/* Return an empty new conflict graph for SIZE elements.  */
 
 static inline ssa_conflicts_p
 ssa_conflicts_new (unsigned size)
@@ -567,7 +600,7 @@ ssa_conflicts_merge (ssa_conflicts_p ptr, unsigned x, unsigned y)
     return;
 
   /* Add a conflict between X and every one Y has.  If the bitmap doesn't
-     exist, then it has already been coalesced, and we dont need to add a 
+     exist, then it has already been coalesced, and we don't need to add a
      conflict.  */
   EXECUTE_IF_SET_IN_BITMAP (ptr->conflicts[y], 0, z, bi)
     if (ptr->conflicts[z])
@@ -588,6 +621,24 @@ ssa_conflicts_merge (ssa_conflicts_p ptr, unsigned x, unsigned y)
 }
 
 
+/* Dump a conflicts graph.  */
+
+static void
+ssa_conflicts_dump (FILE *file, ssa_conflicts_p ptr)
+{
+  unsigned x;
+
+  fprintf (file, "\nConflict graph:\n");
+
+  for (x = 0; x < ptr->size; x++)
+    if (ptr->conflicts[x])
+      {
+       fprintf (dump_file, "%d: ", x);
+       dump_bitmap (file, ptr->conflicts[x]);
+      }
+}
+
+
 /* This structure is used to efficiently record the current status of live 
    SSA_NAMES when building a conflict graph.  
    LIVE_BASE_VAR has a bit set for each base variable which has at least one
@@ -787,9 +838,9 @@ live_track_clear_base_vars (live_track_p ptr)
 
 
 /* Build a conflict graph based on LIVEINFO.  Any partitions which are in the
-   partition view of the var_map liveinfo is based on get entires in the 
+   partition view of the var_map liveinfo is based on get entries in the 
    conflict graph.  Only conflicts between ssa_name partitions with the same 
-   base variableare added.  */
+   base variable are added.  */
 
 static ssa_conflicts_p
 build_ssa_conflict_graph (tree_live_info_p liveinfo)
@@ -807,16 +858,15 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
 
   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator bsi;
-      tree phi;
+      gimple_stmt_iterator gsi;
 
       /* Start with live on exit temporaries.  */
       live_track_init (live, live_on_exit (liveinfo, bb));
 
-      for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
+      for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
         {
          tree var;
-         tree stmt = bsi_stmt (bsi);
+         gimple stmt = gsi_stmt (gsi);
 
          /* A copy between 2 partitions does not introduce an interference 
             by itself.  If they did, you would never be able to coalesce 
@@ -825,13 +875,17 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
             
             This is handled by simply removing the SRC of the copy from the 
             live list, and processing the stmt normally.  */
-         if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+         if (is_gimple_assign (stmt))
            {
-             tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-             tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
-             if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME)
-               live_track_clear_var (live, rhs);
+             tree lhs = gimple_assign_lhs (stmt);
+             tree rhs1 = gimple_assign_rhs1 (stmt);
+             if (gimple_assign_copy_p (stmt)
+                  && TREE_CODE (lhs) == SSA_NAME
+                  && TREE_CODE (rhs1) == SSA_NAME)
+               live_track_clear_var (live, rhs1);
            }
+         else if (is_gimple_debug (stmt))
+           continue;
 
          FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_DEF)
            live_track_process_def (live, var, graph);
@@ -846,8 +900,9 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo)
         There must be a conflict recorded between the result of the PHI and 
         any variables that are live.  Otherwise the out-of-ssa translation 
         may create incorrect code.  */
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
+         gimple phi = gsi_stmt (gsi);
          tree result = PHI_RESULT (phi);
          if (live_track_live_p (live, result))
            live_track_process_def (live, result, graph);
@@ -881,11 +936,11 @@ print_exprs (FILE *f, const char *str1, tree expr1, const char *str2,
    printed and compilation is then terminated.  */
 
 static inline void
-abnormal_corrupt (tree phi, int i)
+abnormal_corrupt (gimple phi, int i)
 {
-  edge e = PHI_ARG_EDGE (phi, i);
-  tree res = PHI_RESULT (phi);
-  tree arg = PHI_ARG_DEF (phi, i);
+  edge e = gimple_phi_arg_edge (phi, i);
+  tree res = gimple_phi_result (phi);
+  tree arg = gimple_phi_arg_def (phi, i);
 
   fprintf (stderr, " Corrupt SSA across abnormal edge BB%d->BB%d\n",
           e->src->index, e->dest->index);
@@ -909,7 +964,7 @@ abnormal_corrupt (tree phi, int i)
 static inline void
 fail_abnormal_edge_coalesce (int x, int y)
 {
-  fprintf (stderr, "\nUnable to coalesce ssa_names %d  and %d ",x, y);
+  fprintf (stderr, "\nUnable to coalesce ssa_names %d and %d",x, y);
   fprintf (stderr, " which are marked as MUST COALESCE.\n");
   print_generic_expr (stderr, ssa_name (x), TDF_SLIM);
   fprintf (stderr, " and  ");
@@ -925,10 +980,10 @@ fail_abnormal_edge_coalesce (int x, int y)
 static var_map
 create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
 {
-  block_stmt_iterator bsi;
+  gimple_stmt_iterator gsi;
   basic_block bb;
   tree var;
-  tree stmt;
+  gimple stmt;
   tree first;
   var_map map;
   ssa_op_iter iter;
@@ -943,28 +998,29 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
   used_in_virtual_ops = BITMAP_ALLOC (NULL);
 #endif
 
-  map = init_var_map (num_ssa_names + 1);
+  map = init_var_map (num_ssa_names);
 
   FOR_EACH_BB (bb)
     {
-      tree phi, arg;
+      tree arg;
 
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         int i;
+         gimple phi = gsi_stmt (gsi);
+         size_t i;
          int ver;
          tree res;
          bool saw_copy = false;
 
-         res = PHI_RESULT (phi);
+         res = gimple_phi_result (phi);
          ver = SSA_NAME_VERSION (res);
          register_ssa_partition (map, res);
 
          /* Register ssa_names and coalesces between the args and the result 
             of all PHI.  */
-         for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+         for (i = 0; i < gimple_phi_num_args (phi); i++)
            {
-             edge e = PHI_ARG_EDGE (phi, i);
+             edge e = gimple_phi_arg_edge (phi, i);
              arg = PHI_ARG_DEF (phi, i);
              if (TREE_CODE (arg) == SSA_NAME)
                register_ssa_partition (map, arg);
@@ -976,7 +1032,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
                  if ((e->flags & EDGE_ABNORMAL) == 0)
                    {
                      int cost = coalesce_cost_edge (e);
-                     if (cost == 1 && single_imm_use_p (arg))
+                     if (cost == 1 && has_single_use (arg))
                        add_cost_one_coalesce (cl, ver, SSA_NAME_VERSION (arg));
                      else
                        add_coalesce (cl, ver, SSA_NAME_VERSION (arg), cost);
@@ -990,27 +1046,32 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
            bitmap_set_bit (used_in_copy, ver);
        }
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
         {
-         stmt = bsi_stmt (bsi);
+         stmt = gsi_stmt (gsi);
+
+         if (is_gimple_debug (stmt))
+           continue;
 
          /* Register USE and DEF operands in each statement.  */
          FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, (SSA_OP_DEF|SSA_OP_USE))
            register_ssa_partition (map, var);
 
          /* Check for copy coalesces.  */
-         switch (TREE_CODE (stmt))
+         switch (gimple_code (stmt))
            {
-           case GIMPLE_MODIFY_STMT:
+           case GIMPLE_ASSIGN:
              {
-               tree op1 = GIMPLE_STMT_OPERAND (stmt, 0);
-               tree op2 = GIMPLE_STMT_OPERAND (stmt, 1);
-               if (TREE_CODE (op1) == SSA_NAME 
-                   && TREE_CODE (op2) == SSA_NAME
-                   && SSA_NAME_VAR (op1) == SSA_NAME_VAR (op2))
+               tree lhs = gimple_assign_lhs (stmt);
+               tree rhs1 = gimple_assign_rhs1 (stmt);
+
+               if (gimple_assign_copy_p (stmt)
+                    && TREE_CODE (lhs) == SSA_NAME
+                   && TREE_CODE (rhs1) == SSA_NAME
+                   && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (rhs1))
                  {
-                   v1 = SSA_NAME_VERSION (op1);
-                   v2 = SSA_NAME_VERSION (op2);
+                   v1 = SSA_NAME_VERSION (lhs);
+                   v2 = SSA_NAME_VERSION (rhs1);
                    cost = coalesce_cost_bb (bb);
                    add_coalesce (cl, v1, v2, cost);
                    bitmap_set_bit (used_in_copy, v1);
@@ -1019,25 +1080,32 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
              }
              break;
 
-           case ASM_EXPR:
+           case GIMPLE_ASM:
              {
                unsigned long noutputs, i;
+               unsigned long ninputs;
                tree *outputs, link;
-               noutputs = list_length (ASM_OUTPUTS (stmt));
+               noutputs = gimple_asm_noutputs (stmt);
+               ninputs = gimple_asm_ninputs (stmt);
                outputs = (tree *) alloca (noutputs * sizeof (tree));
-               for (i = 0, link = ASM_OUTPUTS (stmt); link;
-                    ++i, link = TREE_CHAIN (link))
+               for (i = 0; i < noutputs; ++i) {
+                 link = gimple_asm_output_op (stmt, i);
                  outputs[i] = TREE_VALUE (link);
+                }
 
-               for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
+               for (i = 0; i < ninputs; ++i)
                  {
-                   const char *constraint
-                     = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
-                   tree input = TREE_VALUE (link);
+                    const char *constraint;
+                    tree input;
                    char *end;
                    unsigned long match;
 
-                   if (TREE_CODE (input) != SSA_NAME && !DECL_P (input))
+                   link = gimple_asm_input_op (stmt, i);
+                   constraint
+                     = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+                   input = TREE_VALUE (link);
+
+                   if (TREE_CODE (input) != SSA_NAME)
                      continue;
 
                    match = strtoul (constraint, &end, 10);
@@ -1053,8 +1121,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
                    if (SSA_NAME_VAR (outputs[match]) == SSA_NAME_VAR (input))
                      {
                        cost = coalesce_cost (REG_BR_PROB_BASE, 
-                                             maybe_hot_bb_p (bb),
-                                             false);
+                                             optimize_bb_for_size_p (bb));
                        add_coalesce (cl, v1, v2, cost);
                        bitmap_set_bit (used_in_copy, v1);
                        bitmap_set_bit (used_in_copy, v2);
@@ -1073,12 +1140,9 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
            bitmap_set_bit (used_in_real_ops, DECL_UID (SSA_NAME_VAR (var)));
 
          /* Validate that virtual ops don't get used in funny ways.  */
-         FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_VIRTUALS)
-           {
-             bitmap_set_bit (used_in_virtual_ops, 
-                             DECL_UID (SSA_NAME_VAR (var)));
-           }
-
+         if (gimple_vuse (stmt))
+           bitmap_set_bit (used_in_virtual_ops, 
+                           DECL_UID (SSA_NAME_VAR (gimple_vuse (stmt))));
 #endif /* ENABLE_CHECKING */
        }
     }
@@ -1088,8 +1152,8 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
   first = NULL_TREE;
   for (i = 1; i < num_ssa_names; i++)
     {
-      var = map->partition_to_var[i];
-      if (var != NULL_TREE)
+      var = ssa_name (i);
+      if (var != NULL_TREE && is_gimple_reg (var))
         {
          /* Add coalesces between all the result decls.  */
          if (TREE_CODE (SSA_NAME_VAR (var)) == RESULT_DECL)
@@ -1110,7 +1174,8 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
          /* Mark any default_def variables as being in the coalesce list
             since they will have to be coalesced with the base variable.  If
             not marked as present, they won't be in the coalesce view. */
-         if (gimple_default_def (cfun, SSA_NAME_VAR (var)) == var)
+         if (gimple_default_def (cfun, SSA_NAME_VAR (var)) == var
+             && !has_zero_uses (var))
            bitmap_set_bit (used_in_copy, SSA_NAME_VERSION (var));
        }
     }
@@ -1140,7 +1205,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
 }
 
 
-/* Attempt to coalesce ssa verisons X and Y together using the partition
+/* Attempt to coalesce ssa versions X and Y together using the partition
    mapping in MAP and checking conflicts in GRAPH.  Output any debug info to
    DEBUG, if it is nun-NULL.  */
 
@@ -1213,14 +1278,14 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
                     FILE *debug)
 {
   int x = 0, y = 0;
-  tree var1, var2, phi;
+  tree var1, var2;
   int cost;
   basic_block bb;
   edge e;
   edge_iterator ei;
 
-  /* First, coalece all the copie across abnormal edges.  These are not placed
-     in the coalesce list becase they do not need to be sorted, and simply 
+  /* First, coalesce all the copies across abnormal edges.  These are not placed
+     in the coalesce list because they do not need to be sorted, and simply 
      consume extra memory/compilation time in large programs.  */
 
   FOR_EACH_BB (bb)
@@ -1228,8 +1293,11 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
       FOR_EACH_EDGE (e, ei, bb->preds)
        if (e->flags & EDGE_ABNORMAL)
          {
-           for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+           gimple_stmt_iterator gsi;
+           for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+                gsi_next (&gsi))
              {
+               gimple phi = gsi_stmt (gsi);
                tree res = PHI_RESULT (phi);
                tree arg = PHI_ARG_DEF (phi, e->dest_idx);
                int v1 = SSA_NAME_VERSION (res);
@@ -1263,6 +1331,24 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
     }
 }
 
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_ssa_name_by_var (const void *p)
+{
+  const_tree n = (const_tree) p;
+  return (hashval_t) htab_hash_pointer (SSA_NAME_VAR (n));
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_ssa_name_by_var (const void *p1, const void *p2)
+{
+  const_tree n1 = (const_tree) p1;
+  const_tree n2 = (const_tree) p2;
+  return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
+}
 
 /* Reduce the number of copies by coalescing variables in the function.  Return
    a partition map with the resulting coalesces.  */
@@ -1270,21 +1356,55 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
 extern var_map
 coalesce_ssa_name (void)
 {
-  unsigned num, x;
   tree_live_info_p liveinfo;
   ssa_conflicts_p graph;
   coalesce_list_p cl;
   bitmap used_in_copies = BITMAP_ALLOC (NULL);
   var_map map;
+  unsigned int i;
+  static htab_t ssa_name_hash;
 
   cl = create_coalesce_list ();
   map = create_outofssa_var_map (cl, used_in_copies);
 
+  /* We need to coalesce all names originating same SSA_NAME_VAR
+     so debug info remains undisturbed.  */
+  if (!optimize)
+    {
+      ssa_name_hash = htab_create (10, hash_ssa_name_by_var,
+                                  eq_ssa_name_by_var, NULL);
+      for (i = 1; i < num_ssa_names; i++)
+       {
+         tree a = ssa_name (i);
+
+         if (a
+             && SSA_NAME_VAR (a)
+             && !DECL_ARTIFICIAL (SSA_NAME_VAR (a))
+             && (!has_zero_uses (a) || !SSA_NAME_IS_DEFAULT_DEF (a)))
+           {
+             tree *slot = (tree *) htab_find_slot (ssa_name_hash, a, INSERT);
+
+             if (!*slot)
+               *slot = a;
+             else
+               {
+                 add_coalesce (cl, SSA_NAME_VERSION (a), SSA_NAME_VERSION (*slot),
+                               MUST_COALESCE_COST - 1);
+                 bitmap_set_bit (used_in_copies, SSA_NAME_VERSION (a));
+                 bitmap_set_bit (used_in_copies, SSA_NAME_VERSION (*slot));
+               }
+           }
+       }
+      htab_delete (ssa_name_hash);
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    dump_var_map (dump_file, map);
+
   /* Don't calculate live ranges for variables not in the coalesce list.  */
   partition_view_bitmap (map, used_in_copies, true);
   BITMAP_FREE (used_in_copies);
 
-  if (num_var_partitions (map) <= 1)
+  if (num_var_partitions (map) < 1)
     {
       delete_coalesce_list (cl);
       return map;
@@ -1301,6 +1421,8 @@ coalesce_ssa_name (void)
   /* Build a conflict graph.  */
   graph = build_ssa_conflict_graph (liveinfo);
   delete_tree_live_info (liveinfo);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    ssa_conflicts_dump (dump_file, graph);
 
   sort_coalesce_list (cl);
 
@@ -1313,31 +1435,6 @@ coalesce_ssa_name (void)
   /* First, coalesce all live on entry variables to their base variable. 
      This will ensure the first use is coming from the correct location.  */
 
-  num = num_var_partitions (map);
-  for (x = 0 ; x < num; x++)
-    {
-      tree var = partition_to_var (map, x);
-      tree root;
-
-      if (TREE_CODE (var) != SSA_NAME)
-       continue;
-
-      root = SSA_NAME_VAR (var);
-      if (gimple_default_def (cfun, root) == var)
-        {
-         /* This root variable should have not already been assigned
-            to another partition which is not coalesced with this one.  */
-         gcc_assert (!var_ann (root)->out_of_ssa_tag);
-
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             print_exprs (dump_file, "Must coalesce ", var,
-                          " with the root variable ", root, ".\n");
-           }
-         change_partition_var (map, root, x);
-       }
-    }
-
   if (dump_file && (dump_flags & TDF_DETAILS))
     dump_var_map (dump_file, map);
 
@@ -1351,4 +1448,3 @@ coalesce_ssa_name (void)
 
   return map;
 }
-