OSDN Git Service

PR tree-optimization/23434
[pf3gnuchains/gcc-fork.git] / gcc / tree-outof-ssa.c
index ae24275..3d83036 100644 (file)
@@ -16,8 +16,8 @@ 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.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -32,7 +32,6 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
-#include "errors.h"
 #include "expr.h"
 #include "function.h"
 #include "diagnostic.h"
@@ -46,6 +45,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tree-dump.h"
 #include "tree-ssa-live.h"
 #include "tree-pass.h"
+#include "toplev.h"
 
 /* Flags to pass to remove_ssa_form.  */
 
@@ -53,6 +53,9 @@ Boston, MA 02111-1307, USA.  */
 #define SSANORM_COMBINE_TEMPS          0x2
 #define SSANORM_COALESCE_PARTITIONS    0x4
 
+DEF_VEC_I(int);
+DEF_VEC_ALLOC_I(int,heap);
+
 /* 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
    edges represented as pairs of nodes.
@@ -82,7 +85,7 @@ typedef struct _elim_graph {
   VEC(tree,heap) *nodes;
 
   /*  The predecessor and successor edge list.  */
-  varray_type edge_list;
+  VEC(int,heap) *edge_list;
 
   /* Visited vector.  */
   sbitmap visited;
@@ -155,14 +158,14 @@ create_temp (tree t)
     name = "temp";
   tmp = create_tmp_var (type, name);
 
-  if (DECL_DEBUG_EXPR (t) && DECL_DEBUG_EXPR_IS_FROM (t))
+  if (DECL_DEBUG_EXPR_IS_FROM (t) && DECL_DEBUG_EXPR (t))
     {
-      DECL_DEBUG_EXPR (tmp) = DECL_DEBUG_EXPR (t);  
+      SET_DECL_DEBUG_EXPR (tmp, DECL_DEBUG_EXPR (t));  
       DECL_DEBUG_EXPR_IS_FROM (tmp) = 1;
     }
   else if (!DECL_IGNORED_P (t))
     {
-      DECL_DEBUG_EXPR (tmp) = t;
+      SET_DECL_DEBUG_EXPR (tmp, t);
       DECL_DEBUG_EXPR_IS_FROM (tmp) = 1;
     }
   DECL_ARTIFICIAL (tmp) = DECL_ARTIFICIAL (t);
@@ -220,7 +223,7 @@ new_elim_graph (int size)
 
   g->nodes = VEC_alloc (tree, heap, 30);
   g->const_copies = VEC_alloc (tree, heap, 20);
-  VARRAY_INT_INIT (g->edge_list, 20, "Elimination Edge List");
+  g->edge_list = VEC_alloc (int, heap, 20);
   VARRAY_INT_INIT (g->stack, 30, " Elimination Stack");
   
   g->visited = sbitmap_alloc (size);
@@ -235,7 +238,7 @@ static inline void
 clear_elim_graph (elim_graph g)
 {
   VEC_truncate (tree, g->nodes, 0);
-  VARRAY_POP_ALL (g->edge_list);
+  VEC_truncate (int, g->edge_list, 0);
 }
 
 
@@ -245,6 +248,7 @@ static inline void
 delete_elim_graph (elim_graph g)
 {
   sbitmap_free (g->visited);
+  VEC_free (int, heap, g->edge_list);
   VEC_free (tree, heap, g->const_copies);
   VEC_free (tree, heap, g->nodes);
   free (g);
@@ -280,8 +284,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);
 }
 
 
@@ -293,12 +297,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;
@@ -313,12 +317,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)
@@ -332,12 +336,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)
@@ -672,48 +676,26 @@ coalesce_abnormal_edges (var_map map, conflict_graph graph, root_var_p rv)
          }
 }
 
+/* Coalesce potential copies via PHI arguments.  */
 
-/* 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
+coalesce_phi_operands (var_map map, coalesce_list_p cl)
 {
-  unsigned 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;
-
-  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);
-
-  cl = create_coalesce_list (map);
+  tree phi;
 
-  /* Add all potential copies via PHI arguments to the list.  */
   FOR_EACH_BB (bb)
     {
       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
        {
          tree res = PHI_RESULT (phi);
          int p = var_to_partition (map, res);
+         int x;
+
          if (p == NO_PARTITION)
            continue;
-         for (x = 0; x < (unsigned)PHI_NUM_ARGS (phi); x++)
+
+         for (x = 0; x < PHI_NUM_ARGS (phi); x++)
            {
              tree arg = PHI_ARG_DEF (phi, x);
              int p2;
@@ -724,18 +706,30 @@ coalesce_ssa_name (var_map map, int flags)
                continue;
              p2 = var_to_partition (map, PHI_ARG_DEF (phi, x));
              if (p2 != NO_PARTITION)
-               add_coalesce (cl, p, p2, 1);
+               {
+                 edge e = PHI_ARG_EDGE (phi, x);
+                 add_coalesce (cl, p, p2,
+                               coalesce_cost (EDGE_FREQUENCY (e),
+                                              maybe_hot_bb_p (bb),
+                                              EDGE_CRITICAL_P (e)));
+               }
            }
        }
     }
+}
 
-  /* Coalesce all the result decls together.  */
-  var = NULL_TREE;
-  i = 0;
-  for (x = 0; x < num_var_partitions (map); x++)
+/* Coalesce all the result decls together.  */
+
+static void
+coalesce_result_decls (var_map map, coalesce_list_p cl)
+{
+  unsigned int i, x;
+  tree var = NULL;
+
+  for (i = x = 0; x < num_var_partitions (map); x++)
     {
       tree p = partition_to_var (map, x);
-      if (TREE_CODE (SSA_NAME_VAR(p)) == RESULT_DECL)
+      if (TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL)
        {
          if (var == NULL_TREE)
            {
@@ -743,9 +737,106 @@ coalesce_ssa_name (var_map map, int flags)
              i = x;
            }
          else
-           add_coalesce (cl, i, x, 1);
+           add_coalesce (cl, i, x,
+                         coalesce_cost (EXIT_BLOCK_PTR->frequency,
+                                        maybe_hot_bb_p (EXIT_BLOCK_PTR),
+                                        false));
+       }
+    }
+}
+
+/* Coalesce matching constraints in asms.  */
+
+static void
+coalesce_asm_operands (var_map map, coalesce_list_p cl)
+{
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      block_stmt_iterator bsi;
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+       {
+         tree stmt = bsi_stmt (bsi);
+         unsigned long noutputs, i;
+         tree *outputs, link;
+
+         if (TREE_CODE (stmt) != ASM_EXPR)
+           continue;
+
+         noutputs = list_length (ASM_OUTPUTS (stmt));
+         outputs = (tree *) alloca (noutputs * sizeof (tree));
+         for (i = 0, link = ASM_OUTPUTS (stmt); link;
+              ++i, link = TREE_CHAIN (link))
+           outputs[i] = TREE_VALUE (link);
+
+         for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
+           {
+             const char *constraint
+               = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+             tree input = TREE_VALUE (link);
+             char *end;
+             unsigned long match;
+             int p1, p2;
+
+             if (TREE_CODE (input) != SSA_NAME && !DECL_P (input))
+               continue;
+
+             match = strtoul (constraint, &end, 10);
+             if (match >= noutputs || end == constraint)
+               continue;
+
+             if (TREE_CODE (outputs[match]) != SSA_NAME
+                 && !DECL_P (outputs[match]))
+               continue;
+
+             p1 = var_to_partition (map, outputs[match]);
+             if (p1 == NO_PARTITION)
+               continue;
+             p2 = var_to_partition (map, input);
+             if (p2 == NO_PARTITION)
+               continue;
+
+             add_coalesce (cl, p1, p2, coalesce_cost (REG_BR_PROB_BASE,
+                                                      maybe_hot_bb_p (bb),
+                                                      false));
+           }
        }
     }
+}
+
+/* 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)
+{
+  unsigned num, x;
+  sbitmap live;
+  root_var_p rv;
+  tree_live_info_p liveinfo;
+  conflict_graph graph;
+  coalesce_list_p cl = NULL;
+  sbitmap_iterator sbi;
+
+  if (num_var_partitions (map) <= 1)
+    return NULL;
+
+  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);
+
+  cl = create_coalesce_list (map);
+
+  coalesce_phi_operands (map, cl);
+  coalesce_result_decls (map, cl);
+  coalesce_asm_operands (map, cl);
 
   /* Build a conflict graph.  */
   graph = build_tree_conflict_graph (liveinfo, rv, cl);
@@ -773,14 +864,14 @@ coalesce_ssa_name (var_map map, int flags)
   /* 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));
+  num = num_var_partitions (map);
+  live = sbitmap_alloc (num);
   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);
+      tree var = partition_to_var (map, x);
       if (default_def (SSA_NAME_VAR (var)) == var)
        SET_BIT (live, x);
     }
@@ -793,10 +884,10 @@ coalesce_ssa_name (var_map map, int flags)
 
   /* Assign root variable as partition representative for each live on entry
      partition.  */
-  EXECUTE_IF_SET_IN_SBITMAP (live, 0, x, 
+  EXECUTE_IF_SET_IN_SBITMAP (live, 0, x, sbi)
     {
-      var = root_var (rv, root_var_find (rv, x));
-      ann = var_ann (var);
+      tree var = root_var (rv, root_var_find (rv, x));
+      var_ann_t ann = var_ann (var);
       /* If these aren't already coalesced...  */
       if (partition_to_var (map, x) != var)
        {
@@ -813,7 +904,7 @@ coalesce_ssa_name (var_map map, int flags)
 
          change_partition_var (map, var, x);
        }
-    });
+    }
 
   sbitmap_free (live);
 
@@ -1092,7 +1183,14 @@ coalesce_vars (var_map map, tree_live_info_p liveinfo)
              if (p2 == (unsigned)NO_PARTITION)
                continue;
              if (p != p2)
-               add_coalesce (cl, p, p2, 1);
+               {
+                 edge e = PHI_ARG_EDGE (phi, x);
+
+                 add_coalesce (cl, p, p2, 
+                               coalesce_cost (EDGE_FREQUENCY (e),
+                                              maybe_hot_bb_p (bb),
+                                              EDGE_CRITICAL_P (e)));
+               }
            }
        }
    }