tree-phinodes.c File Reference

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "varray.h"
#include "ggc.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "toplev.h"
#include "gt-tree-phinodes.h"

Include dependency graph for tree-phinodes.c:

Go to the source code of this file.

Defines

#define NUM_BUCKETS   10

Functions

static int ideal_phi_node_len (int)
static void resize_phi_node (tree *, int)
void init_phinodes ()
void fini_phinodes ()
static tree allocate_phi_node ()
static int ideal_phi_node_len ()
static tree make_phi_node ()
void release_phi_node ()
static void resize_phi_node ()
void reserve_phi_args_for_new_edge ()
tree create_phi_node ()
void add_phi_arg ()
static void remove_phi_arg_num ()
void remove_phi_args ()
void remove_phi_node ()
tree phi_reverse ()

Variables

static tree free_phinodes [NUM_BUCKETS-2]
static unsigned long free_phinode_count


Define Documentation

#define NUM_BUCKETS   10
 

Rewriting a function into SSA form can create a huge number of PHIs
   many of which may be thrown away shortly after their creation if jumps
   were threaded through PHI nodes.

   While our garbage collection mechanisms will handle this situation, it
   is extremely wasteful to create nodes and throw them away, especially
   when the nodes can be reused.

   For PR 8361, we can significantly reduce the number of nodes allocated
   and thus the total amount of memory allocated by managing PHIs a
   little.  This additionally helps reduce the amount of work done by the
   garbage collector.  Similar results have been seen on a wider variety
   of tests (such as the compiler itself).

   Right now we maintain our free list on a per-function basis.  It may
   or may not make sense to maintain the free list for the duration of
   a compilation unit.

   We could also use a zone allocator for these objects since they have
   a very well defined lifetime.  If someone wants to experiment with that
   this is the place to try it.

   PHI nodes have different sizes, so we can't have a single list of all
   the PHI nodes as it would be too expensive to walk down that list to
   find a PHI of a suitable size.

   Instead we have an array of lists of free PHI nodes.  The array is
   indexed by the number of PHI alternatives that PHI node can hold.
   Except for the last array member, which holds all remaining PHI
   nodes.

   So to find a free PHI node, we compute its index into the free PHI
   node array and see if there are any elements with an exact match.
   If so, then we are done.  Otherwise, we test the next larger size
   up and continue until we are in the last array element.

   We do not actually walk members of the last array element.  While it
   might allow us to pick up a few reusable PHI nodes, it could potentially
   be very expensive if the program has released a bunch of large PHI nodes,
   but keeps asking for even larger PHI nodes.  Experiments have shown that
   walking the elements of the last array entry would result in finding less
   than .1% additional reusable PHI nodes.

   Note that we can never have less than two PHI argument slots.  Thus,
   the -2 on all the calculations below.   

Definition at line 79 of file tree-phinodes.c.


Function Documentation

void add_phi_arg  ) 
 

Add a new argument to PHI node PHI.  DEF is the incoming reaching
   definition and E is the edge through which DEF reaches PHI.  The new
   argument is added at the end of the argument list.
   If PHI has reached its maximum capacity, add a few slots.  In this case,
   PHI points to the reallocated phi node when we return.   

Definition at line 372 of file tree-phinodes.c.

References bb_for_stmt(), PHI_ARG_CAPACITY, PHI_NUM_ARGS, PHI_RESULT, SET_PHI_ARG_DEF, and SSA_NAME_OCCURS_IN_ABNORMAL_PHI.

00373 {
00374   basic_block bb = e->dest;
00375 
00376   gcc_assert (bb == bb_for_stmt (phi));
00377 
00378   /* We resize PHI nodes upon edge creation.  We should always have
00379      enough room at this point.  */
00380   gcc_assert (PHI_NUM_ARGS (phi) <= PHI_ARG_CAPACITY (phi));
00381 
00382   /* We resize PHI nodes upon edge creation.  We should always have
00383      enough room at this point.  */
00384   gcc_assert (e->dest_idx < (unsigned int) PHI_NUM_ARGS (phi));
00385 
00386   /* Copy propagation needs to know what object occur in abnormal
00387      PHI nodes.  This is a convenient place to record such information.  */
00388   if (e->flags & EDGE_ABNORMAL)
00389     {
00390       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) = 1;
00391       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
00392     }
00393 
00394   SET_PHI_ARG_DEF (phi, e->dest_idx, def);
00395 }

static tree allocate_phi_node  )  [inline, static]
 

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.   

Definition at line 131 of file tree-phinodes.c.

References free_phinodes, PHI_ARG_CAPACITY, and PHI_CHAIN.

Referenced by make_phi_node(), and resize_phi_node().

00132 {
00133   tree phi;
00134   int bucket = NUM_BUCKETS - 2;
00135   int size = (sizeof (struct tree_phi_node)
00136               + (len - 1) * sizeof (struct phi_arg_d));
00137 
00138   if (free_phinode_count)
00139     for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++)
00140       if (free_phinodes[bucket])
00141         break;
00142 
00143   /* If our free list has an element, then use it.  */
00144   if (bucket < NUM_BUCKETS - 2
00145       && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len)
00146     {
00147       free_phinode_count--;
00148       phi = free_phinodes[bucket];
00149       free_phinodes[bucket] = PHI_CHAIN (free_phinodes[bucket]);
00150 #ifdef GATHER_STATISTICS
00151       phi_nodes_reused++;
00152 #endif
00153     }
00154   else
00155     {
00156       phi = ggc_alloc (size);
00157 #ifdef GATHER_STATISTICS
00158       phi_nodes_created++;
00159       tree_node_counts[(int) phi_kind]++;
00160       tree_node_sizes[(int) phi_kind] += size;
00161 #endif
00162     }
00163 
00164   return phi;
00165 }

tree create_phi_node  ) 
 

Create a new PHI node for variable VAR at basic block BB.   

Definition at line 349 of file tree-phinodes.c.

References make_phi_node(), PHI_CHAIN, phi_nodes(), and set_bb_for_stmt().

00350 {
00351   tree phi;
00352 
00353   phi = make_phi_node (var, EDGE_COUNT (bb->preds));
00354 
00355   /* Add the new PHI node to the list of PHI nodes for block BB.  */
00356   PHI_CHAIN (phi) = phi_nodes (bb);
00357   bb->phi_nodes = phi;
00358 
00359   /* Associate BB to the PHI node.  */
00360   set_bb_for_stmt (phi, bb);
00361 
00362   return phi;
00363 }

void fini_phinodes void   ) 
 

Finalize management of PHIs.   

Definition at line 106 of file tree-phinodes.c.

References free_phinodes.

00107 {
00108   int i;
00109 
00110   for (i = 0; i < NUM_BUCKETS - 2; i++)
00111     free_phinodes[i] = NULL;
00112   free_phinode_count = 0;
00113 }

static int ideal_phi_node_len  )  [static]
 

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.

   Rounding up will not result in wasting any memory since the size request
   will be rounded up by the GC system anyway.  [ Note this is not entirely
   true since the original length might have fit on one of the special
   GC pages. ]  By rounding up, we may avoid the need to reallocate the
   PHI node later if we increase the number of arguments for the PHI.   

Definition at line 178 of file tree-phinodes.c.

00179 {
00180   size_t size, new_size;
00181   int log2, new_len;
00182 
00183   /* We do not support allocations of less than two PHI argument slots.  */
00184   if (len < 2)
00185     len = 2;
00186 
00187   /* Compute the number of bytes of the original request.  */
00188   size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d);
00189 
00190   /* Round it up to the next power of two.  */
00191   log2 = ceil_log2 (size);
00192   new_size = 1 << log2;
00193 
00194   /* Now compute and return the number of PHI argument slots given an
00195      ideal size allocation.  */
00196   new_len = len + (new_size - size) / sizeof (struct phi_arg_d);
00197   return new_len;
00198 }

static int ideal_phi_node_len int   )  [static]
 

Referenced by make_phi_node(), and reserve_phi_args_for_new_edge().

void init_phinodes void   ) 
 

Initialize management of PHIs.   

Definition at line 94 of file tree-phinodes.c.

References free_phinodes.

Referenced by init_tree_ssa().

00095 {
00096   int i;
00097 
00098   for (i = 0; i < NUM_BUCKETS - 2; i++)
00099     free_phinodes[i] = NULL;
00100   free_phinode_count = 0;
00101 }

static tree make_phi_node  )  [static]
 

Return a PHI node with LEN argument slots for variable VAR.   

Definition at line 204 of file tree-phinodes.c.

References allocate_phi_node(), ideal_phi_node_len(), make_ssa_name(), PHI_ARG_CAPACITY, PHI_ARG_DEF_TREE, PHI_ARG_IMM_USE_NODE, PHI_NUM_ARGS, SET_PHI_RESULT, TREE_CODE, TREE_SET_CODE, and TREE_TYPE.

Referenced by create_phi_node().

00205 {
00206   tree phi;
00207   int capacity, i;
00208 
00209   capacity = ideal_phi_node_len (len);
00210 
00211   phi = allocate_phi_node (capacity);
00212 
00213   /* We need to clear the entire PHI node, including the argument
00214      portion, because we represent a "missing PHI argument" by placing
00215      NULL_TREE in PHI_ARG_DEF.  */
00216   memset (phi, 0, (sizeof (struct tree_phi_node) - sizeof (struct phi_arg_d)
00217                    + sizeof (struct phi_arg_d) * len));
00218   TREE_SET_CODE (phi, PHI_NODE);
00219   PHI_NUM_ARGS (phi) = len;
00220   PHI_ARG_CAPACITY (phi) = capacity;
00221   TREE_TYPE (phi) = TREE_TYPE (var);
00222   if (TREE_CODE (var) == SSA_NAME)
00223     SET_PHI_RESULT (phi, var);
00224   else
00225     SET_PHI_RESULT (phi, make_ssa_name (var, phi));
00226 
00227   for (i = 0; i < capacity; i++)
00228     {
00229       use_operand_p  imm;
00230       imm = &(PHI_ARG_IMM_USE_NODE (phi, i));
00231       imm->use = &(PHI_ARG_DEF_TREE (phi, i));
00232       imm->prev = NULL;
00233       imm->next = NULL;
00234       imm->stmt = phi;
00235     }
00236   return phi;
00237 }

tree phi_reverse  ) 
 

Reverse the order of PHI nodes in the chain PHI.
   Return the new head of the chain (old last PHI node).   

Definition at line 476 of file tree-phinodes.c.

References NULL_TREE, and PHI_CHAIN.

00477 {
00478   tree prev = NULL_TREE, next;
00479   for (; phi; phi = next)
00480     {
00481       next = PHI_CHAIN (phi);
00482       PHI_CHAIN (phi) = prev;
00483       prev = phi;
00484     }
00485   return prev;
00486 }

void release_phi_node  ) 
 

We no longer need PHI, release it so that it may be reused.   

Definition at line 242 of file tree-phinodes.c.

References delink_imm_use(), PHI_ARG_CAPACITY, PHI_ARG_IMM_USE_NODE, and PHI_NUM_ARGS.

Referenced by process_phi_nodes(), remove_phi_node(), and reserve_phi_args_for_new_edge().

00243 {
00244   int bucket;
00245   int len = PHI_ARG_CAPACITY (phi);
00246   int x;
00247 
00248   for (x = 0; x < PHI_NUM_ARGS (phi); x++)
00249     {
00250       use_operand_p  imm;
00251       imm = &(PHI_ARG_IMM_USE_NODE (phi, x));
00252       delink_imm_use (imm);
00253     }
00254 
00255   bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len;
00256   bucket -= 2;
00257   PHI_CHAIN (phi) = free_phinodes[bucket];
00258   free_phinodes[bucket] = phi;
00259   free_phinode_count++;
00260 }

static void remove_phi_arg_num  )  [static]
 

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.   

Definition at line 403 of file tree-phinodes.c.

References delink_imm_use(), PHI_ARG_IMM_USE_NODE, PHI_NUM_ARGS, relink_imm_use(), and ssa_use_operand_d::use.

Referenced by remove_phi_args().

00404 {
00405   int num_elem = PHI_NUM_ARGS (phi);
00406 
00407   gcc_assert (i < num_elem);
00408 
00409 
00410   /* Delink the item which is being removed.  */
00411   delink_imm_use (&(PHI_ARG_IMM_USE_NODE (phi, i)));
00412 
00413   /* If it is not the last element, move the last element
00414      to the element we want to delete, resetting all the links. */
00415   if (i != num_elem - 1)
00416     {
00417       use_operand_p old_p, new_p;
00418       old_p = &PHI_ARG_IMM_USE_NODE (phi, num_elem - 1);
00419       new_p = &PHI_ARG_IMM_USE_NODE (phi, i);
00420       /* Set use on new node, and link into last element's place.  */
00421       *(new_p->use) = *(old_p->use);
00422       relink_imm_use (new_p, old_p);
00423     }
00424 
00425   /* Shrink the vector and return.  Note that we do not have to clear
00426      PHI_ARG_DEF because the garbage collector will not look at those
00427      elements beyond the first PHI_NUM_ARGS elements of the array.  */
00428   PHI_NUM_ARGS (phi)--;
00429 }

void remove_phi_args  ) 
 

Remove all PHI arguments associated with edge E.   

Definition at line 434 of file tree-phinodes.c.

References PHI_CHAIN, phi_nodes(), and remove_phi_arg_num().

00435 {
00436   tree phi;
00437 
00438   for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
00439     remove_phi_arg_num (phi, e->dest_idx);
00440 }

void remove_phi_node  ) 
 

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.   

Definition at line 446 of file tree-phinodes.c.

References bb_for_stmt(), PHI_CHAIN, phi_nodes(), PHI_RESULT, release_phi_node(), and release_ssa_name().

00447 {
00448   tree *loc;
00449 
00450   if (prev)
00451     {
00452       loc = &PHI_CHAIN (prev);
00453     }
00454   else
00455     {
00456       for (loc = &(bb_for_stmt (phi)->phi_nodes);
00457            *loc != phi;
00458            loc = &PHI_CHAIN (*loc))
00459         ;
00460     }
00461 
00462   /* Remove PHI from the chain.  */
00463   *loc = PHI_CHAIN (phi);
00464 
00465   /* If we are deleting the PHI node, then we should release the
00466      SSA_NAME node so that it can be reused.  */
00467   release_phi_node (phi);
00468   release_ssa_name (PHI_RESULT (phi));
00469 }

void reserve_phi_args_for_new_edge  ) 
 

Reserve PHI arguments for a new edge to basic block BB.   

Definition at line 311 of file tree-phinodes.c.

References ideal_phi_node_len(), NULL_TREE, PHI_ARG_CAPACITY, PHI_CHAIN, PHI_NUM_ARGS, PHI_RESULT, release_phi_node(), resize_phi_node(), SET_PHI_ARG_DEF, and SSA_NAME_DEF_STMT.

00312 {
00313   tree *loc;
00314   int len = EDGE_COUNT (bb->preds);
00315   int cap = ideal_phi_node_len (len + 4);
00316 
00317   for (loc = &(bb->phi_nodes);
00318        *loc;
00319        loc = &PHI_CHAIN (*loc))
00320     {
00321       if (len > PHI_ARG_CAPACITY (*loc))
00322         {
00323           tree old_phi = *loc;
00324 
00325           resize_phi_node (loc, cap);
00326 
00327           /* The result of the phi is defined by this phi node.  */
00328           SSA_NAME_DEF_STMT (PHI_RESULT (*loc)) = *loc;
00329 
00330           release_phi_node (old_phi);
00331         }
00332 
00333       /* We represent a "missing PHI argument" by placing NULL_TREE in
00334          the corresponding slot.  If PHI arguments were added
00335          immediately after an edge is created, this zeroing would not
00336          be necessary, but unfortunately this is not the case.  For
00337          example, the loop optimizer duplicates several basic blocks,
00338          redirects edges, and then fixes up PHI arguments later in
00339          batch.  */
00340       SET_PHI_ARG_DEF (*loc, len - 1, NULL_TREE);
00341 
00342       PHI_NUM_ARGS (*loc)++;
00343     }
00344 }

static void resize_phi_node  )  [static]
 

Resize an existing PHI node.  The only way is up.  Return the
   possibly relocated phi.   

Definition at line 266 of file tree-phinodes.c.

References allocate_phi_node(), PHI_ARG_CAPACITY, PHI_ARG_DEF_TREE, PHI_ARG_IMM_USE_NODE, PHI_NUM_ARGS, relink_imm_use_stmt(), and ssa_use_operand_d::use.

00267 {
00268   int old_size, i;
00269   tree new_phi;
00270 
00271   gcc_assert (len > PHI_ARG_CAPACITY (*phi));
00272 
00273   /* The garbage collector will not look at the PHI node beyond the
00274      first PHI_NUM_ARGS elements.  Therefore, all we have to copy is a
00275      portion of the PHI node currently in use.  */
00276   old_size = (sizeof (struct tree_phi_node)
00277              + (PHI_NUM_ARGS (*phi) - 1) * sizeof (struct phi_arg_d));
00278 
00279   new_phi = allocate_phi_node (len);
00280 
00281   memcpy (new_phi, *phi, old_size);
00282 
00283   for (i = 0; i < PHI_NUM_ARGS (new_phi); i++)
00284     {
00285       use_operand_p imm, old_imm;
00286       imm = &(PHI_ARG_IMM_USE_NODE (new_phi, i));
00287       old_imm = &(PHI_ARG_IMM_USE_NODE (*phi, i));
00288       imm->use = &(PHI_ARG_DEF_TREE (new_phi, i));
00289       relink_imm_use_stmt (imm, old_imm, new_phi);
00290     }
00291 
00292   PHI_ARG_CAPACITY (new_phi) = len;
00293 
00294   for (i = PHI_NUM_ARGS (new_phi); i < len; i++)
00295     {
00296       use_operand_p imm;
00297       imm = &(PHI_ARG_IMM_USE_NODE (new_phi, i));
00298       imm->use = &(PHI_ARG_DEF_TREE (new_phi, i));
00299       imm->prev = NULL;
00300       imm->next = NULL;
00301       imm->stmt = new_phi;
00302     }
00303 
00304 
00305   *phi = new_phi;
00306 }

static void resize_phi_node tree *  ,
int 
[static]
 

Referenced by reserve_phi_args_for_new_edge().


Variable Documentation

unsigned long free_phinode_count [static]
 

Definition at line 81 of file tree-phinodes.c.

tree free_phinodes[NUM_BUCKETS-2] [static]
 

Definition at line 80 of file tree-phinodes.c.

Referenced by allocate_phi_node(), fini_phinodes(), and init_phinodes().


Generated on Sun Sep 17 18:03:50 2006 for Tree SSA by  doxygen 1.4.6