aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog38
-rw-r--r--gcc/tree-pretty-print.c4
-rw-r--r--gcc/tree-ssa-operands.c575
-rw-r--r--gcc/tree-ssa-operands.h45
4 files changed, 345 insertions, 317 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 004ec9c9a80..e9a397ea476 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,41 @@
+2006-12-18 Andrew MacLeod <amacleod@redhat.com>
+
+ * tree-ssa-operands.h (struct vdef_optype_d): Rename to voptype_d.
+ (struct vuse_optype_d): Delete.
+ (SSA_OPERAND_MEMORY_SIZE): Delete.
+ (struct ssa_operand_memory_d): Change mem array to size one.
+ (NUM_VOP_FREE_BUCKETS): Define.
+ (free_vuses, free_vdefs): Replace with vop_free_buckets array.
+ (vdef_ops, vuse_ops, struct ssa_operand_iterator_d): Use voptype_d type.
+ * tree-pretty-print.c (dump_vops): Use voptype_d type.
+ * tree-ssa-operands.c (vop_free_bucket_size): New. Number of operands
+ which fit into a chunk of memory from a specific bucket.
+ (vop_free_bucket_index): New. Find correct size memory bucket.
+ (init_vop_buckets): New. Initialize VOP free memory buckets.
+ (add_vop_to_freelist): New. Add a VOP to the correct free list.
+ (ssa_operand_mem_size): New. Current size of an operand memory chunk.
+ (init_ssa_operands): Initialize operand memory and free lists.
+ (fini_ssa_operands): Remove references to free_vuses and free_vdefs.
+ (ssa_operand_alloc): Use graduated size memory allocation.
+ (APPEND_OP_AFTER, MOVE_HEAD_AFTER, MOVE_HEAD_TO_FREELIST,
+ INITIALIZE_USE): Remove.
+ (alloc_vop): New. Allocate a virtual operand.
+ (alloc_vdef, alloc_vuse): Delete.
+ (add_def_op, add_use_op): Directly setup pointers.
+ (add_vop): New. Add a virtual operand.
+ (add_vuse_op, add_vdef_op): Call add_vop.
+ (realloc_vop): New. Reallocate a virtual operand.
+ (realloc_vdef, realloc_vuse): Call realloc_vop.
+ (finalize_ssa_def_ops): Delete. Move content to finalize_ssa_defs.
+ (finalize_ssa_defs): Optimize for common case, remove code based on
+ sorted pointers which was a waste of time.
+ (finalize_ssa_use_ops): Delete. Move content to finalize_ssa_uses.
+ (finalize_ssa_uses): Update last pointer.
+ (finalize_ssa_vdef_ops): Delete. Move content to finalize_ssa_vdefs.
+ (finalize_ssa_vdefs, finalize_ssa_vuse_ops): Use voptype_d and
+ directly manipulate pointers.
+ (copy_virtual_operands): Use voptype_d, and no need to update pointers.
+
2006-12-18 Nathan Sidwell <nathan@codesourcery.com>
* config/rs6000/rs6000.md (*movdf_hardfloat32): Use %X format to
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index e78b95c4f3b..e4f85c13275 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2692,8 +2692,8 @@ newline_and_indent (pretty_printer *buffer, int spc)
static void
dump_vops (pretty_printer *buffer, tree stmt, int spc, int flags)
{
- struct vdef_optype_d *vdefs;
- struct vuse_optype_d *vuses;
+ struct voptype_d *vdefs;
+ struct voptype_d *vuses;
int i, n;
if (!ssa_operands_active () || !stmt_references_memory_p (stmt))
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index c11fe5b80f5..a577727243e 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -265,6 +265,95 @@ ssa_operands_active (void)
}
+/* VOPs are of variable sized, so the free list maps "free buckets" to the
+ following table:
+ bucket # operands
+ ------ ----------
+ 0 1
+ 1 2
+ ...
+ 15 16
+ 16 17-24
+ 17 25-32
+ 18 31-40
+ ...
+ 29 121-128
+ Any VOPs larger than this are simply added to the largest bucket when they
+ are freed. */
+
+
+/* Return the number of operands used in bucket BUCKET. */
+
+static inline int
+vop_free_bucket_size (int bucket)
+{
+#ifdef ENABLE_CHECKING
+ gcc_assert (bucket >= 0 && bucket < NUM_VOP_FREE_BUCKETS);
+#endif
+ if (bucket < 16)
+ return bucket + 1;
+ return (bucket - 13) * 8;
+}
+
+
+/* For a vop of NUM operands, return the bucket NUM belongs to. If NUM is
+ beyond the end of the bucket table, return -1. */
+
+static inline int
+vop_free_bucket_index (int num)
+{
+ gcc_assert (num > 0);
+
+ /* Sizes 1 through 16 use buckets 0-15. */
+ if (num <= 16)
+ return num - 1;
+ /* Buckets 16 - 45 represent 17 through 256 in 8 unit chunks. */
+ if (num < 256)
+ return 14 + (num - 1) / 8;
+ return -1;
+}
+
+
+/* Initialize the VOP free buckets. */
+
+static inline void
+init_vop_buckets (void)
+{
+ int x;
+
+ for (x = 0; x < NUM_VOP_FREE_BUCKETS; x++)
+ gimple_ssa_operands (cfun)->vop_free_buckets[x] = NULL;
+}
+
+
+/* Add PTR to the appropriate VOP bucket. */
+
+static inline void
+add_vop_to_freelist (voptype_p ptr)
+{
+ int bucket = vop_free_bucket_index (VUSE_VECT_NUM_ELEM (ptr->usev));
+
+ /* Too large, use the largest bucket so its not a complete throw away. */
+ if (bucket == -1)
+ bucket = NUM_VOP_FREE_BUCKETS - 1;
+
+ ptr->next = gimple_ssa_operands (cfun)->vop_free_buckets[bucket];
+ gimple_ssa_operands (cfun)->vop_free_buckets[bucket] = ptr;
+}
+
+
+/* These are the sizes of the operand memory buffer which gets allocated each
+ time more operands space is required. The final value is the amount that is
+ allocated every time after that. */
+
+#define OP_SIZE_INIT 0
+#define OP_SIZE_1 30
+#define OP_SIZE_2 110
+#define OP_SIZE_3 511
+
+/* Current size of the operand memory buffer. */
+static unsigned int ssa_operand_mem_size;
+
/* Initialize the operand cache routines. */
void
@@ -283,9 +372,11 @@ init_ssa_operands (void)
gcc_assert (gimple_ssa_operands (cfun)->operand_memory == NULL);
gcc_assert (gimple_ssa_operands (cfun)->mpt_table == NULL);
- gimple_ssa_operands (cfun)->operand_memory_index = SSA_OPERAND_MEMORY_SIZE;
+ gimple_ssa_operands (cfun)->operand_memory_index = ssa_operand_mem_size;
gimple_ssa_operands (cfun)->ops_active = true;
memset (&clobber_stats, 0, sizeof (clobber_stats));
+ init_vop_buckets ();
+ ssa_operand_mem_size = OP_SIZE_INIT;
}
@@ -315,8 +406,6 @@ fini_ssa_operands (void)
gimple_ssa_operands (cfun)->free_defs = NULL;
gimple_ssa_operands (cfun)->free_uses = NULL;
- gimple_ssa_operands (cfun)->free_vuses = NULL;
- gimple_ssa_operands (cfun)->free_vdefs = NULL;
while ((ptr = gimple_ssa_operands (cfun)->operand_memory) != NULL)
{
@@ -362,13 +451,32 @@ ssa_operand_alloc (unsigned size)
{
char *ptr;
- gcc_assert (size <= SSA_OPERAND_MEMORY_SIZE);
-
if (gimple_ssa_operands (cfun)->operand_memory_index + size
- >= SSA_OPERAND_MEMORY_SIZE)
+ >= ssa_operand_mem_size)
{
struct ssa_operand_memory_d *ptr;
- ptr = GGC_NEW (struct ssa_operand_memory_d);
+
+ if (ssa_operand_mem_size == OP_SIZE_INIT)
+ ssa_operand_mem_size = OP_SIZE_1 * sizeof (struct voptype_d);
+ else
+ if (ssa_operand_mem_size == OP_SIZE_1 * sizeof (struct voptype_d))
+ ssa_operand_mem_size = OP_SIZE_2 * sizeof (struct voptype_d);
+ else
+ ssa_operand_mem_size = OP_SIZE_3 * sizeof (struct voptype_d);
+
+ /* Go right to the maximum size if the request is too large. */
+ if (size > ssa_operand_mem_size)
+ ssa_operand_mem_size = OP_SIZE_3 * sizeof (struct voptype_d);
+
+ /* Fail if there is not enough space. If thre are this many operands
+ required, first make sure there isn't a different probem causing this
+ many operands. If the decision is that this is OK, then we can
+ specially allocate a buffer just for this request. */
+ gcc_assert (size <= ssa_operand_mem_size);
+
+ ptr = (struct ssa_operand_memory_d *)
+ ggc_alloc (sizeof (struct ssa_operand_memory_d)
+ + ssa_operand_mem_size - 1);
ptr->next = gimple_ssa_operands (cfun)->operand_memory;
gimple_ssa_operands (cfun)->operand_memory = ptr;
gimple_ssa_operands (cfun)->operand_memory_index = 0;
@@ -380,6 +488,8 @@ ssa_operand_alloc (unsigned size)
}
+/* Allocate a DEF operand. */
+
static inline struct def_optype_d *
alloc_def (void)
{
@@ -392,11 +502,13 @@ alloc_def (void)
}
else
ret = (struct def_optype_d *)
- ssa_operand_alloc (sizeof (struct def_optype_d));
+ ssa_operand_alloc (sizeof (struct def_optype_d));
return ret;
}
+/* Allocate a USE operand. */
+
static inline struct use_optype_d *
alloc_use (void)
{
@@ -408,50 +520,40 @@ alloc_use (void)
= gimple_ssa_operands (cfun)->free_uses->next;
}
else
- ret = (struct use_optype_d *)ssa_operand_alloc (sizeof (struct use_optype_d));
+ ret = (struct use_optype_d *)
+ ssa_operand_alloc (sizeof (struct use_optype_d));
return ret;
}
+/* Allocate a vop with NUM elements. */
-
-static inline struct vdef_optype_d *
-alloc_vdef (int num)
+static inline struct voptype_d *
+alloc_vop (int num)
{
- struct vdef_optype_d *ret;
- /* Eliminate free list for the moment. */
-#if 0
- if (free_vdefs)
+ struct voptype_d *ret = NULL;
+ int alloc_size = 0;
+
+ int bucket = vop_free_bucket_index (num);
+ if (bucket != -1)
{
- ret = free_vdefs;
- free_vdefs = free_vdefs->next;
+ /* If there is a free operand, use it. */
+ if (gimple_ssa_operands (cfun)->vop_free_buckets[bucket] != NULL)
+ {
+ ret = gimple_ssa_operands (cfun)->vop_free_buckets[bucket];
+ gimple_ssa_operands (cfun)->vop_free_buckets[bucket] =
+ gimple_ssa_operands (cfun)->vop_free_buckets[bucket]->next;
+ }
+ else
+ alloc_size = vop_free_bucket_size(bucket);
}
else
-#endif
- ret = (struct vdef_optype_d *)ssa_operand_alloc (
- sizeof (struct vdef_optype_d) + (num - 1) * sizeof (vuse_element_t));
- VUSE_VECT_NUM_ELEM (ret->usev) = num;
- return ret;
-}
-
-
+ alloc_size = num;
+ if (alloc_size > 0)
+ ret = (struct voptype_d *)ssa_operand_alloc (
+ sizeof (struct voptype_d) + (alloc_size - 1) * sizeof (vuse_element_t));
-static inline struct vuse_optype_d *
-alloc_vuse (int num)
-{
- struct vuse_optype_d *ret;
-/* No free list for the moment. */
-#if 0
- if (free_vuses)
- {
- ret = free_vuses;
- free_vuses = free_vuses->next;
- }
- else
-#endif
- ret = (struct vuse_optype_d *)ssa_operand_alloc (
- sizeof (struct vuse_optype_d) + (num - 1) * sizeof (vuse_element_t));
VUSE_VECT_NUM_ELEM (ret->usev) = num;
return ret;
}
@@ -472,138 +574,111 @@ set_virtual_use_link (use_operand_p ptr, tree stmt)
link_imm_use (ptr, *(ptr->use));
}
-/* Appends ELT after TO, and moves the TO pointer to ELT. */
-
-#define APPEND_OP_AFTER(ELT, TO) \
- do \
- { \
- (TO)->next = (ELT); \
- (TO) = (ELT); \
- } while (0)
-
-/* Appends head of list FROM after TO, and move both pointers
- to their successors. */
-
-#define MOVE_HEAD_AFTER(FROM, TO) \
- do \
- { \
- APPEND_OP_AFTER (FROM, TO); \
- (FROM) = (FROM)->next; \
- } while (0)
-
-/* Moves OP to appropriate freelist. OP is set to its successor. */
-
-#define MOVE_HEAD_TO_FREELIST(OP, TYPE) \
- do \
- { \
- TYPE##_optype_p next = (OP)->next; \
- (OP)->next \
- = gimple_ssa_operands (cfun)->free_##TYPE##s; \
- gimple_ssa_operands (cfun)->free_##TYPE##s = (OP);\
- (OP) = next; \
- } while (0)
-
-/* Initializes immediate use at USE_PTR to value VAL, and links it to the list
- of immediate uses. STMT is the current statement. */
-
-#define INITIALIZE_USE(USE_PTR, VAL, STMT) \
- do \
- { \
- (USE_PTR)->use = (VAL); \
- link_imm_use_stmt ((USE_PTR), *(VAL), (STMT)); \
- } while (0)
-
-/* Adds OP to the list of defs after LAST, and moves
- LAST to the new element. */
+
+/* Adds OP to the list of defs after LAST. */
static inline def_optype_p
-add_def_op (tree *op, def_optype_p *last)
+add_def_op (tree *op, def_optype_p last)
{
def_optype_p new;
new = alloc_def ();
DEF_OP_PTR (new) = op;
- APPEND_OP_AFTER (new, *last);
+ last->next = new;
+ new->next = NULL;
return new;
}
-/* Adds OP to the list of uses of statement STMT after LAST, and moves
- LAST to the new element. */
+
+/* Adds OP to the list of uses of statement STMT after LAST. */
static inline use_optype_p
-add_use_op (tree stmt, tree *op, use_optype_p *last)
+add_use_op (tree stmt, tree *op, use_optype_p last)
{
use_optype_p new;
new = alloc_use ();
- INITIALIZE_USE (USE_OP_PTR (new), op, stmt);
- APPEND_OP_AFTER (new, *last);
+ USE_OP_PTR (new)->use = op;
+ link_imm_use_stmt (USE_OP_PTR (new), *op, stmt);
+ last->next = new;
+ new->next = NULL;
return new;
}
-/* Adds OP to the list of vuses of statement STMT after LAST, and moves
- LAST to the new element. */
-static inline vuse_optype_p
-add_vuse_op (tree stmt, tree op, int num, vuse_optype_p *last)
+/* Return a virtual op pointer with NUM elements which are all initialized to OP
+ and are linked into the immeidate uses for STMT. The new vop is appended
+ after PREV. */
+
+static inline voptype_p
+add_vop (tree stmt, tree op, int num, voptype_p prev)
{
- vuse_optype_p new;
+ voptype_p new;
int x;
- new = alloc_vuse (num);
+ new = alloc_vop (num);
for (x = 0; x < num; x++)
{
+ VUSE_OP_PTR (new, x)->prev = NULL;
SET_VUSE_OP (new, x, op);
- INITIALIZE_USE (VUSE_OP_PTR (new, x), &new->usev.uses[x].use_var, stmt);
+ VUSE_OP_PTR (new, x)->use = &new->usev.uses[x].use_var;
+ link_imm_use_stmt (VUSE_OP_PTR (new, x), new->usev.uses[x].use_var, stmt);
}
- APPEND_OP_AFTER (new, *last);
+ if (prev)
+ prev->next = new;
+ new->next = NULL;
return new;
}
-/* Adds OP to the list of vdefs of statement STMT after LAST, and moves
+/* Adds OP to the list of vuses of statement STMT after LAST, and moves
LAST to the new element. */
-static inline vdef_optype_p
-add_vdef_op (tree stmt, tree op, int num, vdef_optype_p *last)
+static inline voptype_p
+add_vuse_op (tree stmt, tree op, int num, voptype_p last)
{
- int x;
- vdef_optype_p new;
+ voptype_p new = add_vop (stmt, op, num, last);
+ VDEF_RESULT (new) = NULL_TREE;
+ return new;
+}
- new = alloc_vdef (num);
- VDEF_RESULT (new) = op;
- for (x = 0; x < num; x++)
- {
- SET_VDEF_OP (new, x, op);
- INITIALIZE_USE (VDEF_OP_PTR (new, x), &new->usev.uses[x].use_var, stmt);
- }
- APPEND_OP_AFTER (new, *last);
+/* Adds OP to the list of vdefs of statement STMT after LAST, and moves
+ LAST to the new element. */
+
+static inline voptype_p
+add_vdef_op (tree stmt, tree op, int num, voptype_p last)
+{
+ voptype_p new = add_vop (stmt, op, num, last);
+ VDEF_RESULT (new) = op;
return new;
}
+
+/* Reallocate the virtual operand PTR so that it has NUM_ELEM use slots. ROOT
+ is the head of the operand list it belongs to. */
-struct vdef_optype_d *
-realloc_vdef (struct vdef_optype_d *ptr, int num_elem)
+static inline struct voptype_d *
+realloc_vop (struct voptype_d *ptr, int num_elem, struct voptype_d **root)
{
int x, lim;
- tree val, stmt;
- struct vdef_optype_d *ret, *tmp;
+ tree stmt, val;
+ struct voptype_d *ret, *tmp;
if (VUSE_VECT_NUM_ELEM (ptr->usev) == num_elem)
return ptr;
-
- val = VDEF_RESULT (ptr);
+
+ val = VUSE_OP (ptr, 0);
if (TREE_CODE (val) == SSA_NAME)
val = SSA_NAME_VAR (val);
- stmt = USE_STMT (VDEF_OP_PTR (ptr, 0));
+ stmt = USE_STMT (VUSE_OP_PTR (ptr, 0));
/* Delink all the existing uses. */
for (x = 0; x < VUSE_VECT_NUM_ELEM (ptr->usev); x++)
{
- use_operand_p use_p = VDEF_OP_PTR (ptr, x);
+ use_operand_p use_p = VUSE_OP_PTR (ptr, x);
delink_imm_use (use_p);
}
@@ -615,23 +690,22 @@ realloc_vdef (struct vdef_optype_d *ptr, int num_elem)
}
/* It is growing. Allocate a new one and replace the old one. */
- tmp = ptr;
- ret = add_vdef_op (stmt, val, num_elem, &ptr);
- ret->next = NULL;
- ptr = tmp;
+ ret = add_vuse_op (stmt, val, num_elem, ptr);
+ /* Clear PTR and add its memory to the free list. */
lim = VUSE_VECT_NUM_ELEM (ptr->usev);
memset (ptr, 0,
- sizeof (struct vdef_optype_d) + sizeof (vuse_element_t) * (lim- 1));
+ sizeof (struct voptype_d) + sizeof (vuse_element_t) * (lim- 1));
+ add_vop_to_freelist (ptr);
/* Now simply remove the old one. */
- if (VDEF_OPS (stmt) == ptr)
+ if (*root == ptr)
{
- VDEF_OPS (stmt) = ret;
+ *root = ret;
return ret;
}
else
- for (tmp = VDEF_OPS (stmt);
+ for (tmp = *root;
tmp != NULL && tmp->next != ptr;
tmp = tmp->next)
{
@@ -642,79 +716,51 @@ realloc_vdef (struct vdef_optype_d *ptr, int num_elem)
/* The pointer passed in isn't in STMT's VDEF lists. */
gcc_unreachable ();
}
+
+/* Reallocate the PTR vdef so that it has NUM_ELEM use slots. */
-struct vuse_optype_d *
-realloc_vuse (struct vuse_optype_d *ptr, int num_elem)
+struct voptype_d *
+realloc_vdef (struct voptype_d *ptr, int num_elem)
{
- int x, lim;
tree val, stmt;
- struct vuse_optype_d *ret, *tmp;
+ struct voptype_d *ret;
- if (VUSE_VECT_NUM_ELEM (ptr->usev) == num_elem)
- return ptr;
+ val = VDEF_RESULT (ptr);
+ stmt = USE_STMT (VDEF_OP_PTR (ptr, 0));
+ ret = realloc_vop (ptr, num_elem, &(VDEF_OPS (stmt)));
+ VDEF_RESULT (ret) = val;
+ return ret;
+}
- val = VUSE_OP (ptr, 0);
- if (TREE_CODE (val) == SSA_NAME)
- val = SSA_NAME_VAR (val);
- stmt = USE_STMT (VUSE_OP_PTR (ptr, 0));
+/* Reallocate the PTR vuse so that it has NUM_ELEM use slots. */
- /* Delink all the existing uses. */
- for (x = 0; x < VUSE_VECT_NUM_ELEM (ptr->usev); x++)
- {
- use_operand_p use_p = VUSE_OP_PTR (ptr, x);
- delink_imm_use (use_p);
- }
-
- /* If we want less space, simply use this one, and shrink the size. */
- if (VUSE_VECT_NUM_ELEM (ptr->usev) > num_elem)
- {
- VUSE_VECT_NUM_ELEM (ptr->usev) = num_elem;
- return ptr;
- }
-
- /* It is growing. Allocate a new one and replace the old one. */
- tmp = ptr;
- ret = add_vuse_op (stmt, val, num_elem, &ptr);
- ret->next = NULL;
- ptr = tmp;
-
- lim = VUSE_VECT_NUM_ELEM (ptr->usev);
- memset (ptr, 0,
- sizeof (struct vuse_optype_d) + sizeof (vuse_element_t) * (lim - 1));
-
- /* Now simply link it in, find the node which points to this one. */
- if (VUSE_OPS (stmt) == ptr)
- {
- VUSE_OPS (stmt) = ret;
- return ret;
- }
- else
- for (tmp = VUSE_OPS (stmt);
- tmp != NULL && tmp->next != ptr;
- tmp = tmp->next)
- {
- tmp->next = ret;
- return ret;
- }
+struct voptype_d *
+realloc_vuse (struct voptype_d *ptr, int num_elem)
+{
+ tree stmt;
+ struct voptype_d *ret;
- /* The pointer passed in isn't in STMT's VUSE lists. */
- gcc_unreachable ();
+ stmt = USE_STMT (VUSE_OP_PTR (ptr, 0));
+ ret = realloc_vop (ptr, num_elem, &(VUSE_OPS (stmt)));
+ return ret;
}
+
/* Takes elements from build_defs and turns them into def operands of STMT.
- TODO -- Given that def operands list is not necessarily sorted, merging
- the operands this way does not make much sense.
- -- Make build_defs VEC of tree *. */
+ TODO -- Make build_defs VEC of tree *. */
static inline void
-finalize_ssa_def_ops (tree stmt)
+finalize_ssa_defs (tree stmt)
{
unsigned new_i;
struct def_optype_d new_list;
def_optype_p old_ops, last;
- tree *old_base;
+ unsigned int num = VEC_length (tree, build_defs);
+
+ /* There should only be a single real definition per assignment. */
+ gcc_assert ((stmt && TREE_CODE (stmt) != GIMPLE_MODIFY_STMT) || num <= 1);
new_list.next = NULL;
last = &new_list;
@@ -722,35 +768,11 @@ finalize_ssa_def_ops (tree stmt)
old_ops = DEF_OPS (stmt);
new_i = 0;
- while (old_ops && new_i < VEC_length (tree, build_defs))
- {
- tree *new_base = (tree *) VEC_index (tree, build_defs, new_i);
- old_base = DEF_OP_PTR (old_ops);
-
- if (old_base == new_base)
- {
- /* if variables are the same, reuse this node. */
- MOVE_HEAD_AFTER (old_ops, last);
- new_i++;
- }
- else if (old_base < new_base)
- {
- /* if old is less than new, old goes to the free list. */
- MOVE_HEAD_TO_FREELIST (old_ops, def);
- }
- else
- {
- /* This is a new operand. */
- add_def_op (new_base, &last);
- new_i++;
- }
- }
-
- /* If there is anything remaining in the build_defs list, simply emit it. */
- for ( ; new_i < VEC_length (tree, build_defs); new_i++)
- add_def_op ((tree *) VEC_index (tree, build_defs, new_i), &last);
- last->next = NULL;
+ /* Check for the common case of 1 def that hasn't changed. */
+ if (old_ops && old_ops->next == NULL && num == 1
+ && (tree *) VEC_index (tree, build_defs, 0) == DEF_OP_PTR (old_ops))
+ return;
/* If there is anything in the old list, free it. */
if (old_ops)
@@ -759,6 +781,10 @@ finalize_ssa_def_ops (tree stmt)
gimple_ssa_operands (cfun)->free_defs = old_ops;
}
+ /* If there is anything remaining in the build_defs list, simply emit it. */
+ for ( ; new_i < num; new_i++)
+ last = add_def_op ((tree *) VEC_index (tree, build_defs, new_i), last);
+
/* Now set the stmt's operands. */
DEF_OPS (stmt) = new_list.next;
@@ -769,36 +795,36 @@ finalize_ssa_def_ops (tree stmt)
for (ptr = DEF_OPS (stmt); ptr; ptr = ptr->next)
x++;
- gcc_assert (x == VEC_length (tree, build_defs));
+ gcc_assert (x == num);
}
#endif
}
-/* This routine will create stmt operands for STMT from the def build list. */
-
-static void
-finalize_ssa_defs (tree stmt)
-{
- unsigned int num = VEC_length (tree, build_defs);
-
- /* There should only be a single real definition per assignment. */
- gcc_assert ((stmt && TREE_CODE (stmt) != GIMPLE_MODIFY_STMT) || num <= 1);
-
- /* If there is an old list, often the new list is identical, or close, so
- find the elements at the beginning that are the same as the vector. */
- finalize_ssa_def_ops (stmt);
-}
/* Takes elements from build_uses and turns them into use operands of STMT.
TODO -- Make build_uses VEC of tree *. */
static inline void
-finalize_ssa_use_ops (tree stmt)
+finalize_ssa_uses (tree stmt)
{
unsigned new_i;
struct use_optype_d new_list;
use_optype_p old_ops, ptr, last;
+#ifdef ENABLE_CHECKING
+ {
+ unsigned x;
+ unsigned num = VEC_length (tree, build_uses);
+
+ /* If the pointer to the operand is the statement itself, something is
+ wrong. It means that we are pointing to a local variable (the
+ initial call to update_stmt_operands does not pass a pointer to a
+ statement). */
+ for (x = 0; x < num; x++)
+ gcc_assert (*((tree *)VEC_index (tree, build_uses, x)) != stmt);
+ }
+#endif
+
new_list.next = NULL;
last = &new_list;
@@ -815,9 +841,9 @@ finalize_ssa_use_ops (tree stmt)
/* Now create nodes for all the new nodes. */
for (new_i = 0; new_i < VEC_length (tree, build_uses); new_i++)
- add_use_op (stmt, (tree *) VEC_index (tree, build_uses, new_i), &last);
-
- last->next = NULL;
+ last = add_use_op (stmt,
+ (tree *) VEC_index (tree, build_uses, new_i),
+ last);
/* Now set the stmt's operands. */
USE_OPS (stmt) = new_list.next;
@@ -833,38 +859,17 @@ finalize_ssa_use_ops (tree stmt)
#endif
}
-/* Return a new use operand vector for STMT, comparing to OLD_OPS_P. */
-
-static void
-finalize_ssa_uses (tree stmt)
-{
-#ifdef ENABLE_CHECKING
- {
- unsigned x;
- unsigned num = VEC_length (tree, build_uses);
-
- /* If the pointer to the operand is the statement itself, something is
- wrong. It means that we are pointing to a local variable (the
- initial call to update_stmt_operands does not pass a pointer to a
- statement). */
- for (x = 0; x < num; x++)
- gcc_assert (*((tree *)VEC_index (tree, build_uses, x)) != stmt);
- }
-#endif
- finalize_ssa_use_ops (stmt);
-}
-
/* Takes elements from BUILD_VDEFS and turns them into vdef operands of
STMT. FIXME, for now VDEF operators should have a single operand
in their RHS. */
static inline void
-finalize_ssa_vdef_ops (tree stmt)
+finalize_ssa_vdefs (tree stmt)
{
unsigned new_i;
- struct vdef_optype_d new_list;
- vdef_optype_p old_ops, ptr, last;
+ struct voptype_d new_list;
+ voptype_p old_ops, ptr, last;
stmt_ann_t ann = stmt_ann (stmt);
/* Set the symbols referenced by STMT. */
@@ -906,37 +911,43 @@ finalize_ssa_vdef_ops (tree stmt)
if (old_uid == new_uid)
{
/* If the symbols are the same, reuse the existing operand. */
- MOVE_HEAD_AFTER (old_ops, last);
+ last->next = old_ops;
+ last = old_ops;
+ old_ops = old_ops->next;
+ last->next = NULL;
set_virtual_use_link (VDEF_OP_PTR (last, 0), stmt);
new_i++;
}
else if (old_uid < new_uid)
{
/* If old is less than new, old goes to the free list. */
+ voptype_p next;
delink_imm_use (VDEF_OP_PTR (old_ops, 0));
- MOVE_HEAD_TO_FREELIST (old_ops, vdef);
+ next = old_ops->next;
+ add_vop_to_freelist (old_ops);
+ old_ops = next;
}
else
{
/* This is a new operand. */
- add_vdef_op (stmt, op, 1, &last);
+ last = add_vdef_op (stmt, op, 1, last);
new_i++;
}
}
/* If there is anything remaining in BUILD_VDEFS, simply emit it. */
for ( ; new_i < VEC_length (tree, build_vdefs); new_i++)
- add_vdef_op (stmt, VEC_index (tree, build_vdefs, new_i), 1, &last);
-
- last->next = NULL;
+ last = add_vdef_op (stmt, VEC_index (tree, build_vdefs, new_i), 1, last);
/* If there is anything in the old list, free it. */
if (old_ops)
{
- for (ptr = old_ops; ptr; ptr = ptr->next)
- delink_imm_use (VDEF_OP_PTR (ptr, 0));
- old_ops->next = gimple_ssa_operands (cfun)->free_vdefs;
- gimple_ssa_operands (cfun)->free_vdefs = old_ops;
+ for (ptr = old_ops; ptr; ptr = last)
+ {
+ last = ptr->next;
+ delink_imm_use (VDEF_OP_PTR (ptr, 0));
+ add_vop_to_freelist (ptr);
+ }
}
/* Now set STMT's operands. */
@@ -954,14 +965,6 @@ finalize_ssa_vdef_ops (tree stmt)
}
-static void
-finalize_ssa_vdefs (tree stmt)
-{
- finalize_ssa_vdef_ops (stmt);
-}
-
-
-
/* Takes elements from BUILD_VUSES and turns them into VUSE operands of
STMT. */
@@ -970,8 +973,7 @@ finalize_ssa_vuse_ops (tree stmt)
{
unsigned new_i;
int old_i;
- struct vuse_optype_d new_list;
- vuse_optype_p old_ops, last;
+ voptype_p old_ops, last;
VEC(tree,heap) *new_ops;
stmt_ann_t ann;
@@ -1042,9 +1044,7 @@ finalize_ssa_vuse_ops (tree stmt)
{
for (old_i = 0; old_i < VUSE_NUM (old_ops); old_i++)
delink_imm_use (VUSE_OP_PTR (old_ops, old_i));
- old_ops->next = gimple_ssa_operands (cfun)->free_vuses;
- gimple_ssa_operands (cfun)->free_vuses = old_ops;
-
+ add_vop_to_freelist (old_ops);
VUSE_OPS (stmt) = NULL;
}
@@ -1054,15 +1054,12 @@ finalize_ssa_vuse_ops (tree stmt)
tree op;
unsigned i;
- new_list.next = NULL;
- last = &new_list;
- add_vuse_op (stmt, NULL, VEC_length (tree, new_ops), &last);
- last->next = NULL;
+ last = add_vuse_op (stmt, NULL, VEC_length (tree, new_ops), NULL);
for (i = 0; VEC_iterate (tree, new_ops, i, op); i++)
SET_USE (VUSE_OP_PTR (last, (int) i), op);
- VUSE_OPS (stmt) = new_list.next;
+ VUSE_OPS (stmt) = last;
}
#ifdef ENABLE_CHECKING
@@ -2391,10 +2388,10 @@ void
copy_virtual_operands (tree dest, tree src)
{
int i, n;
- vuse_optype_p src_vuses, dest_vuses;
- vdef_optype_p src_vdefs, dest_vdefs;
- struct vuse_optype_d vuse;
- struct vdef_optype_d vdef;
+ voptype_p src_vuses, dest_vuses;
+ voptype_p src_vdefs, dest_vdefs;
+ struct voptype_d vuse;
+ struct voptype_d vdef;
stmt_ann_t dest_ann;
VDEF_OPS (dest) = NULL;
@@ -2421,8 +2418,7 @@ copy_virtual_operands (tree dest, tree src)
for (src_vuses = VUSE_OPS (src); src_vuses; src_vuses = src_vuses->next)
{
n = VUSE_NUM (src_vuses);
- dest_vuses = add_vuse_op (dest, NULL_TREE, n, &dest_vuses);
- dest_vuses->next = NULL;
+ dest_vuses = add_vuse_op (dest, NULL_TREE, n, dest_vuses);
for (i = 0; i < n; i++)
SET_USE (VUSE_OP_PTR (dest_vuses, i), VUSE_OP (src_vuses, i));
@@ -2435,8 +2431,7 @@ copy_virtual_operands (tree dest, tree src)
for (src_vdefs = VDEF_OPS (src); src_vdefs; src_vdefs = src_vdefs->next)
{
n = VUSE_NUM (src_vdefs);
- dest_vdefs = add_vdef_op (dest, NULL_TREE, n, &dest_vdefs);
- dest_vdefs->next = NULL;
+ dest_vdefs = add_vdef_op (dest, NULL_TREE, n, dest_vdefs);
VDEF_RESULT (dest_vdefs) = VDEF_RESULT (src_vdefs);
for (i = 0; i < n; i++)
SET_USE (VUSE_OP_PTR (dest_vdefs, i), VUSE_OP (src_vdefs, i));
diff --git a/gcc/tree-ssa-operands.h b/gcc/tree-ssa-operands.h
index 1bcbe952e69..10fd1459996 100644
--- a/gcc/tree-ssa-operands.h
+++ b/gcc/tree-ssa-operands.h
@@ -98,32 +98,28 @@ typedef struct vuse_vec_d *vuse_vec_p;
#define VUSE_ELEMENT_VAR(V,X) (VUSE_VECT_ELEMENT ((V),(X)).use_var)
-/* This represents the VDEFS for a stmt. */
-struct vdef_optype_d
+/* This represents the virtual ops of a stmt. */
+struct voptype_d
{
- struct vdef_optype_d *next;
+ struct voptype_d *next;
tree def_var;
vuse_vec_t usev;
};
-typedef struct vdef_optype_d *vdef_optype_p;
+typedef struct voptype_d *voptype_p;
-/* This represents the VUSEs for a stmt. */
-struct vuse_optype_d
-{
- struct vuse_optype_d *next;
- vuse_vec_t usev;
-};
-typedef struct vuse_optype_d *vuse_optype_p;
-
-
-#define SSA_OPERAND_MEMORY_SIZE (511 * sizeof (struct vuse_optype_d))
-
+/* This structure represents a variable sized buffer which is allocated by the
+ operand memory manager. Operands are subalocated out of this block. The
+ MEM array varies in size. */
+
struct ssa_operand_memory_d GTY((chain_next("%h.next")))
{
struct ssa_operand_memory_d *next;
- char mem[SSA_OPERAND_MEMORY_SIZE];
+ char mem[1];
};
+/* Number of different size free buckets for virtual operands. */
+#define NUM_VOP_FREE_BUCKETS 29
+
/* Per-function operand caches. */
struct ssa_operands GTY(()) {
struct ssa_operand_memory_d *operand_memory;
@@ -133,8 +129,7 @@ struct ssa_operands GTY(()) {
struct def_optype_d * GTY ((skip (""))) free_defs;
struct use_optype_d * GTY ((skip (""))) free_uses;
- struct vuse_optype_d * GTY ((skip (""))) free_vuses;
- struct vdef_optype_d * GTY ((skip (""))) free_vdefs;
+ struct voptype_d * GTY ((skip (""))) vop_free_buckets[NUM_VOP_FREE_BUCKETS];
VEC(tree,heap) * GTY ((skip (""))) mpt_table;
};
@@ -146,8 +141,8 @@ struct stmt_operands_d
struct use_optype_d * use_ops;
/* Virtual operands (VDEF, VUSE). */
- struct vdef_optype_d * vdef_ops;
- struct vuse_optype_d * vuse_ops;
+ struct voptype_d * vdef_ops;
+ struct voptype_d * vuse_ops;
/* Sets of memory symbols loaded and stored. */
bitmap stores;
@@ -206,8 +201,8 @@ typedef struct stmt_operands_d *stmt_operands_p;
#define PHI_ARG_INDEX_FROM_USE(USE) phi_arg_index_from_use (USE)
-extern struct vdef_optype_d *realloc_vdef (struct vdef_optype_d *, int);
-extern struct vuse_optype_d *realloc_vuse (struct vuse_optype_d *, int);
+extern struct voptype_d *realloc_vdef (struct voptype_d *, int);
+extern struct voptype_d *realloc_vuse (struct voptype_d *, int);
extern void init_ssa_operands (void);
extern void fini_ssa_operands (void);
@@ -249,9 +244,9 @@ typedef struct ssa_operand_iterator_d
{
def_optype_p defs;
use_optype_p uses;
- vuse_optype_p vuses;
- vdef_optype_p vdefs;
- vdef_optype_p mayuses;
+ voptype_p vuses;
+ voptype_p vdefs;
+ voptype_p mayuses;
enum ssa_op_iter_type iter_type;
int phi_i;
int num_phi;