OSDN Git Service

(ASM_SPEC): Undefine (to stop -Qy being passed on to GAS) but do not define,
[pf3gnuchains/gcc-fork.git] / gcc / tree-phinodes.c
index fdeb57a..91bff61 100644 (file)
@@ -123,6 +123,47 @@ phinodes_print_statistics (void)
 }
 #endif
 
+/* Allocate a PHI node with at least LEN arguments.  If the free list
+   happens to contain a PHI node with LEN arguments or more, return
+   that one.  */
+
+static inline tree
+allocate_phi_node (int len)
+{
+  tree phi;
+  int bucket = NUM_BUCKETS - 2;
+  int size = (sizeof (struct tree_phi_node)
+             + (len - 1) * sizeof (struct phi_arg_d));
+
+  if (free_phinode_count)
+    for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
+      if (free_phinodes[bucket])
+       break;
+
+  /* If our free list has an element, then use it.  */
+  if (bucket < NUM_BUCKETS - 2
+      && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len)
+    {
+      free_phinode_count--;
+      phi = free_phinodes[bucket];
+      free_phinodes[bucket] = PHI_CHAIN (free_phinodes[bucket]);
+#ifdef GATHER_STATISTICS
+      phi_nodes_reused++;
+#endif
+    }
+  else
+    {
+      phi = ggc_alloc (size);
+#ifdef GATHER_STATISTICS
+      phi_nodes_created++;
+      tree_node_counts[(int) phi_kind]++;
+      tree_node_sizes[(int) phi_kind] += size;
+#endif
+    }
+
+  return phi;
+}
+
 /* Given LEN, the original number of requested PHI arguments, return
    a new, "ideal" length for the PHI node.  The "ideal" length rounds
    the total size of the PHI node up to the next power of two bytes.
@@ -161,47 +202,24 @@ ideal_phi_node_len (int len)
    definitions created when a variable is used without a preceding
    definition).  */
 
-tree
+static tree
 make_phi_node (tree var, int len)
 {
   tree phi;
-  int size;
-  int bucket = NUM_BUCKETS - 2;
-
-  len = ideal_phi_node_len (len);
+  int capacity;
 
-  size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d);
+  capacity = ideal_phi_node_len (len);
 
-  if (free_phinode_count)
-    for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
-      if (free_phinodes[bucket])
-       break;
+  phi = allocate_phi_node (capacity);
 
-  /* If our free list has an element, then use it.  */
-  if (bucket < NUM_BUCKETS - 2
-      && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len)
-    {
-      free_phinode_count--;
-      phi = free_phinodes[bucket];
-      free_phinodes[bucket] = PHI_CHAIN (free_phinodes[bucket]);
-#ifdef GATHER_STATISTICS
-      phi_nodes_reused++;
-#endif
-    }
-  else
-    {
-      phi = ggc_alloc (size);
-#ifdef GATHER_STATISTICS
-      phi_nodes_created++;
-      tree_node_counts[(int) phi_kind]++;
-      tree_node_sizes[(int) phi_kind] += size;
-#endif
-
-    }
-
-  memset (phi, 0, size);
+  /* We need to clear the entire PHI node, including the argument
+     portion, because we represent a "missing PHI argument" by placing
+     NULL_TREE in PHI_ARG_DEF.  */
+  memset (phi, 0, (sizeof (struct tree_phi_node) - sizeof (struct phi_arg_d)
+                  + sizeof (struct phi_arg_d) * len));
   TREE_SET_CODE (phi, PHI_NODE);
-  PHI_ARG_CAPACITY (phi) = len;
+  PHI_NUM_ARGS (phi) = len;
+  PHI_ARG_CAPACITY (phi) = capacity;
   TREE_TYPE (phi) = TREE_TYPE (var);
   if (TREE_CODE (var) == SSA_NAME)
     SET_PHI_RESULT (phi, var);
@@ -232,56 +250,62 @@ release_phi_node (tree phi)
 static void
 resize_phi_node (tree *phi, int len)
 {
-  int size, old_size;
+  int old_size;
   tree new_phi;
-  int i, old_len, bucket = NUM_BUCKETS - 2;
 
-  gcc_assert (len >= PHI_ARG_CAPACITY (*phi));
+  gcc_assert (len > PHI_ARG_CAPACITY (*phi));
 
-  /* Note that OLD_SIZE is guaranteed to be smaller than SIZE.  */
+  /* The garbage collector will not look at the PHI node beyond the
+     first PHI_NUM_ARGS elements.  Therefore, all we have to copy is a
+     portion of the PHI node currently in use.  */
   old_size = (sizeof (struct tree_phi_node)
-            + (PHI_ARG_CAPACITY (*phi) - 1) * sizeof (struct phi_arg_d));
-  size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d);
+            + (PHI_NUM_ARGS (*phi) - 1) * sizeof (struct phi_arg_d));
 
-  if (free_phinode_count)
-    for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
-      if (free_phinodes[bucket])
-       break;
-
-  /* If our free list has an element, then use it.  */
-  if (bucket < NUM_BUCKETS - 2
-      && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len)
-    {
-      free_phinode_count--;
-      new_phi = free_phinodes[bucket];
-      free_phinodes[bucket] = PHI_CHAIN (free_phinodes[bucket]);
-#ifdef GATHER_STATISTICS
-      phi_nodes_reused++;
-#endif
-    }
-  else
-    {
-      new_phi = ggc_alloc (size);
-#ifdef GATHER_STATISTICS
-      phi_nodes_created++;
-      tree_node_counts[(int) phi_kind]++;
-      tree_node_sizes[(int) phi_kind] += size;
-#endif
-    }
+  new_phi = allocate_phi_node (len);
 
   memcpy (new_phi, *phi, old_size);
 
-  old_len = PHI_ARG_CAPACITY (new_phi);
   PHI_ARG_CAPACITY (new_phi) = len;
 
-  for (i = old_len; i < len; i++)
+  *phi = new_phi;
+}
+
+/* Reserve PHI arguments for a new edge to basic block BB.  */
+
+void
+reserve_phi_args_for_new_edge (basic_block bb)
+{
+  tree *loc;
+  int len = EDGE_COUNT (bb->preds);
+  int cap = ideal_phi_node_len (len + 4);
+
+  for (loc = &(bb_ann (bb)->phi_nodes);
+       *loc;
+       loc = &PHI_CHAIN (*loc))
     {
-      SET_PHI_ARG_DEF (new_phi, i, NULL_TREE);
-      PHI_ARG_EDGE (new_phi, i) = NULL;
-      PHI_ARG_NONZERO (new_phi, i) = false;
-    }
+      if (len > PHI_ARG_CAPACITY (*loc))
+       {
+         tree old_phi = *loc;
 
-  *phi = new_phi;
+         resize_phi_node (loc, cap);
+
+         /* The result of the phi is defined by this phi node.  */
+         SSA_NAME_DEF_STMT (PHI_RESULT (*loc)) = *loc;
+
+         release_phi_node (old_phi);
+       }
+
+      /* We represent a "missing PHI argument" by placing NULL_TREE in
+        the corresponding slot.  If PHI arguments were added
+        immediately after an edge is created, this zeroing would not
+        be necessary, but unfortunately this is not the case.  For
+        example, the loop optimizer duplicates several basic blocks,
+        redirects edges, and then fixes up PHI arguments later in
+        batch.  */
+      SET_PHI_ARG_DEF (*loc, len - 1, NULL_TREE);
+
+      PHI_NUM_ARGS (*loc)++;
+    }
 }
 
 /* Create a new PHI node for variable VAR at basic block BB.  */
@@ -293,10 +317,6 @@ create_phi_node (tree var, basic_block bb)
 
   phi = make_phi_node (var, EDGE_COUNT (bb->preds));
 
-  /* This is a new phi node, so note that is has not yet been
-     rewritten.  */
-  PHI_REWRITTEN (phi) = 0;
-
   /* Add the new PHI node to the list of PHI nodes for block BB.  */
   PHI_CHAIN (phi) = phi_nodes (bb);
   bb_ann (bb)->phi_nodes = phi;
@@ -314,95 +334,38 @@ create_phi_node (tree var, basic_block bb)
    PHI points to the reallocated phi node when we return.  */
 
 void
-add_phi_arg (tree *phi, tree def, edge e)
+add_phi_arg (tree phi, tree def, edge e)
 {
-  int i = PHI_NUM_ARGS (*phi);
+  basic_block bb = e->dest;
 
-  if (i >= PHI_ARG_CAPACITY (*phi))
-    {
-      tree old_phi = *phi;
+  gcc_assert (bb == bb_for_stmt (phi));
 
-      /* Resize the phi.  Unfortunately, this may also relocate it.  */
-      resize_phi_node (phi, ideal_phi_node_len (i + 4));
+  /* We resize PHI nodes upon edge creation.  We should always have
+     enough room at this point.  */
+  gcc_assert (PHI_NUM_ARGS (phi) <= PHI_ARG_CAPACITY (phi));
 
-      /* The result of the phi is defined by this phi node.  */
-      SSA_NAME_DEF_STMT (PHI_RESULT (*phi)) = *phi;
-
-      /* If the PHI was relocated, update the PHI chains appropriately and
-        release the old PHI node.  */
-      if (*phi != old_phi)
-       {
-         /* Extract the basic block for the PHI from the PHI's annotation
-            rather than the edge.  This works better as the edge's
-            destination may not currently be the block with the PHI
-            node if we are in the process of threading the edge to
-            a new destination.  */
-         basic_block bb = bb_for_stmt (*phi);
-
-         release_phi_node (old_phi);
-
-         /* Update the list head if replacing the first listed phi.  */
-         if (phi_nodes (bb) == old_phi)
-           bb_ann (bb)->phi_nodes = *phi;
-         else
-           {
-             /* Traverse the list looking for the phi node to chain to.  */
-             tree p;
-
-             for (p = phi_nodes (bb);
-                  p && PHI_CHAIN (p) != old_phi;
-                  p = PHI_CHAIN (p))
-               ;
-
-             gcc_assert (p);
-             PHI_CHAIN (p) = *phi;
-           }
-       }
-    }
+  /* We resize PHI nodes upon edge creation.  We should always have
+     enough room at this point.  */
+  gcc_assert (e->dest_idx < (unsigned int) PHI_NUM_ARGS (phi));
 
   /* Copy propagation needs to know what object occur in abnormal
      PHI nodes.  This is a convenient place to record such information.  */
   if (e->flags & EDGE_ABNORMAL)
     {
       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) = 1;
-      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (*phi)) = 1;
+      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
     }
 
-  SET_PHI_ARG_DEF (*phi, i, def);
-  PHI_ARG_EDGE (*phi, i) = e;
-  PHI_ARG_NONZERO (*phi, i) = false;
-  PHI_NUM_ARGS (*phi)++;
-}
-
-/* Remove a PHI argument from PHI.  BLOCK is the predecessor block where
-   the PHI argument is coming from.  */
-
-void
-remove_phi_arg (tree phi, basic_block block)
-{
-  int i, num_elem = PHI_NUM_ARGS (phi);
-
-  for (i = 0; i < num_elem; i++)
-    {
-      basic_block src_bb;
-
-      src_bb = PHI_ARG_EDGE (phi, i)->src;
-
-      if (src_bb == block)
-       {
-         remove_phi_arg_num (phi, i);
-         return;
-       }
-    }
+  SET_PHI_ARG_DEF (phi, e->dest_idx, def);
+  PHI_ARG_NONZERO (phi, e->dest_idx) = false;
 }
 
+/* Remove the Ith argument from PHI's argument list.  This routine
+   implements removal by swapping the last alternative with the
+   alternative we want to delete and then shrinking the vector, which
+   is consistent with how we remove an edge from the edge vector.  */
 
-/* Remove the Ith argument from PHI's argument list.  This routine assumes
-   ordering of alternatives in the vector is not important and implements
-   removal by swapping the last alternative with the alternative we want to
-   delete, then shrinking the vector.  */
-
-void
+static void
 remove_phi_arg_num (tree phi, int i)
 {
   int num_elem = PHI_NUM_ARGS (phi);
@@ -414,17 +377,27 @@ remove_phi_arg_num (tree phi, int i)
   if (i != num_elem - 1)
     {
       SET_PHI_ARG_DEF (phi, i, PHI_ARG_DEF (phi, num_elem - 1));
-      PHI_ARG_EDGE (phi, i) = PHI_ARG_EDGE (phi, num_elem - 1);
       PHI_ARG_NONZERO (phi, i) = PHI_ARG_NONZERO (phi, num_elem - 1);
     }
 
-  /* Shrink the vector and return.  */
-  SET_PHI_ARG_DEF (phi, num_elem - 1, NULL_TREE);
-  PHI_ARG_EDGE (phi, num_elem - 1) = NULL;
-  PHI_ARG_NONZERO (phi, num_elem - 1) = false;
+  /* Shrink the vector and return.  Note that we do not have to clear
+     PHI_ARG_DEF or PHI_ARG_NONZERO because the garbage collector will
+     not look at those elements beyond the first PHI_NUM_ARGS elements
+     of the array.  */
   PHI_NUM_ARGS (phi)--;
 }
 
+/* Remove all PHI arguments associated with edge E.  */
+
+void
+remove_phi_args (edge e)
+{
+  tree phi;
+
+  for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
+    remove_phi_arg_num (phi, e->dest_idx);
+}
+
 /* Remove PHI node PHI from basic block BB.  If PREV is non-NULL, it is
    used as the node immediately before PHI in the linked list.  */
 
@@ -474,10 +447,10 @@ remove_all_phi_nodes_for (bitmap vars)
   FOR_EACH_BB (bb)
     {
       /* Build a new PHI list for BB without variables in VARS.  */
-      tree phi, new_phi_list, last_phi, next;
+      tree phi, new_phi_list, next;
+      tree *lastp = &new_phi_list;
 
-      last_phi = new_phi_list = NULL_TREE;
-      for (phi = phi_nodes (bb), next = NULL; phi; phi = next)
+      for (phi = phi_nodes (bb); phi; phi = next)
        {
          tree var = SSA_NAME_VAR (PHI_RESULT (phi));
 
@@ -490,13 +463,8 @@ remove_all_phi_nodes_for (bitmap vars)
                 Note that fact in PHI_REWRITTEN.  */
              PHI_REWRITTEN (phi) = 1;
 
-             if (new_phi_list == NULL_TREE)
-               new_phi_list = last_phi = phi;
-             else
-               {
-                 PHI_CHAIN (last_phi) = phi;
-                 last_phi = phi;
-               }
+             *lastp = phi;
+             lastp = &PHI_CHAIN (phi);
            }
          else
            {
@@ -508,8 +476,7 @@ remove_all_phi_nodes_for (bitmap vars)
        }
 
       /* Make sure the last node in the new list has no successors.  */
-      if (last_phi)
-       PHI_CHAIN (last_phi) = NULL_TREE;
+      *lastp = NULL;
       bb_ann (bb)->phi_nodes = new_phi_list;
 
 #if defined ENABLE_CHECKING
@@ -522,6 +489,21 @@ remove_all_phi_nodes_for (bitmap vars)
     }
 }
 
+/* Reverse the order of PHI nodes in the chain PHI.
+   Return the new head of the chain (old last PHI node).  */
+
+tree
+phi_reverse (tree phi)
+{
+  tree prev = NULL_TREE, next;
+  for (; phi; phi = next)
+    {
+      next = PHI_CHAIN (phi);
+      PHI_CHAIN (phi) = prev;
+      prev = phi;
+    }
+  return prev;
+}
 
 #include "gt-tree-phinodes.h"