2010-05-14 Steven G. Kargl <kargl@gcc.gnu.org>
[official-gcc.git] / gcc / vec.c
blob078bcc636539891e25d35a9cbcfc01ca9d318217
1 /* Vector API for GNU compiler.
2 Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
3 Contributed by Nathan Sidwell <nathan@codesourcery.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* This file is compiled twice: once for the generator programs
22 once for the compiler. */
23 #ifdef GENERATOR_FILE
24 #include "bconfig.h"
25 #else
26 #include "config.h"
27 #endif
29 #include "system.h"
30 #include "ggc.h"
31 #include "vec.h"
32 #include "coretypes.h"
33 #include "toplev.h"
34 #include "hashtab.h"
36 struct vec_prefix
38 unsigned num;
39 unsigned alloc;
40 void *vec[1];
44 #ifdef GATHER_STATISTICS
46 /* Store information about each particular vector. */
47 struct vec_descriptor
49 const char *function;
50 const char *file;
51 int line;
52 size_t allocated;
53 size_t times;
54 size_t peak;
58 /* Hashtable mapping vec addresses to descriptors. */
59 static htab_t vec_desc_hash;
61 /* Hashtable helpers. */
62 static hashval_t
63 hash_descriptor (const void *p)
65 const struct vec_descriptor *const d =
66 (const struct vec_descriptor *) p;
67 return htab_hash_pointer (d->file) + d->line;
69 static int
70 eq_descriptor (const void *p1, const void *p2)
72 const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
73 const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
74 return d->file == l->file && d->function == l->function && d->line == l->line;
77 /* Hashtable converting address of allocated field to loc descriptor. */
78 static htab_t ptr_hash;
79 struct ptr_hash_entry
81 void *ptr;
82 struct vec_descriptor *loc;
83 size_t allocated;
86 /* Hash table helpers functions. */
87 static hashval_t
88 hash_ptr (const void *p)
90 const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
92 return htab_hash_pointer (d->ptr);
95 static int
96 eq_ptr (const void *p1, const void *p2)
98 const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
100 return (p->ptr == p2);
103 /* Return descriptor for given call site, create new one if needed. */
104 static struct vec_descriptor *
105 vec_descriptor (const char *name, int line, const char *function)
107 struct vec_descriptor loc;
108 struct vec_descriptor **slot;
110 loc.file = name;
111 loc.line = line;
112 loc.function = function;
113 if (!vec_desc_hash)
114 vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
116 slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc,
117 INSERT);
118 if (*slot)
119 return *slot;
120 *slot = XCNEW (struct vec_descriptor);
121 (*slot)->file = name;
122 (*slot)->line = line;
123 (*slot)->function = function;
124 (*slot)->allocated = 0;
125 (*slot)->peak = 0;
126 return *slot;
129 /* Account the overhead. */
130 static void
131 register_overhead (struct vec_prefix *ptr, size_t size,
132 const char *name, int line, const char *function)
134 struct vec_descriptor *loc = vec_descriptor (name, line, function);
135 struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
136 PTR *slot;
138 p->ptr = ptr;
139 p->loc = loc;
140 p->allocated = size;
141 if (!ptr_hash)
142 ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
143 slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT);
144 gcc_assert (!*slot);
145 *slot = p;
147 loc->allocated += size;
148 if (loc->peak < loc->allocated)
149 loc->peak += loc->allocated;
150 loc->times++;
153 /* Notice that the pointer has been freed. */
154 static void
155 free_overhead (struct vec_prefix *ptr)
157 PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr),
158 NO_INSERT);
159 struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
160 p->loc->allocated -= p->allocated;
161 htab_clear_slot (ptr_hash, slot);
162 free (p);
165 void
166 vec_heap_free (void *ptr)
168 free_overhead ((struct vec_prefix *)ptr);
169 free (ptr);
171 #endif
173 /* Calculate the new ALLOC value, making sure that RESERVE slots are
174 free. If EXACT grow exactly, otherwise grow exponentially. */
176 static inline unsigned
177 calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact)
179 unsigned alloc = 0;
180 unsigned num = 0;
182 gcc_assert (reserve >= 0);
184 if (pfx)
186 alloc = pfx->alloc;
187 num = pfx->num;
189 else if (!reserve)
190 /* If there's no prefix, and we've not requested anything, then we
191 will create a NULL vector. */
192 return 0;
194 /* We must have run out of room. */
195 gcc_assert (alloc - num < (unsigned) reserve);
197 if (exact)
198 /* Exact size. */
199 alloc = num + reserve;
200 else
202 /* Exponential growth. */
203 if (!alloc)
204 alloc = 4;
205 else if (alloc < 16)
206 /* Double when small. */
207 alloc = alloc * 2;
208 else
209 /* Grow slower when large. */
210 alloc = (alloc * 3 / 2);
212 /* If this is still too small, set it to the right size. */
213 if (alloc < num + reserve)
214 alloc = num + reserve;
216 return alloc;
219 /* Ensure there are at least RESERVE free slots in VEC. If EXACT grow
220 exactly, else grow exponentially. As a special case, if VEC is
221 NULL and RESERVE is 0, no vector will be created. The vector's
222 trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
223 sized elements. */
225 static void *
226 vec_gc_o_reserve_1 (void *vec, int reserve, size_t vec_offset, size_t elt_size,
227 bool exact MEM_STAT_DECL)
229 struct vec_prefix *pfx = (struct vec_prefix *) vec;
230 unsigned alloc = calculate_allocation (pfx, reserve, exact);
232 if (!alloc)
234 if (pfx)
235 ggc_free (pfx);
236 return NULL;
239 vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
240 ((struct vec_prefix *)vec)->alloc = alloc;
241 if (!pfx)
242 ((struct vec_prefix *)vec)->num = 0;
244 return vec;
247 /* Ensure there are at least RESERVE free slots in VEC, growing
248 exponentially. If RESERVE < 0 grow exactly, else grow
249 exponentially. As a special case, if VEC is NULL, and RESERVE is
250 0, no vector will be created. */
252 void *
253 vec_gc_p_reserve (void *vec, int reserve MEM_STAT_DECL)
255 return vec_gc_o_reserve_1 (vec, reserve,
256 offsetof (struct vec_prefix, vec),
257 sizeof (void *), false
258 PASS_MEM_STAT);
261 /* Ensure there are at least RESERVE free slots in VEC, growing
262 exactly. If RESERVE < 0 grow exactly, else grow exponentially. As
263 a special case, if VEC is NULL, and RESERVE is 0, no vector will be
264 created. */
266 void *
267 vec_gc_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
269 return vec_gc_o_reserve_1 (vec, reserve,
270 offsetof (struct vec_prefix, vec),
271 sizeof (void *), true
272 PASS_MEM_STAT);
275 /* As for vec_gc_p_reserve, but for object vectors. The vector's
276 trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
277 sized elements. */
279 void *
280 vec_gc_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
281 MEM_STAT_DECL)
283 return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
284 PASS_MEM_STAT);
287 /* As for vec_gc_p_reserve_exact, but for object vectors. The
288 vector's trailing array is at VEC_OFFSET offset and consists of
289 ELT_SIZE sized elements. */
291 void *
292 vec_gc_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
293 size_t elt_size MEM_STAT_DECL)
295 return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
296 PASS_MEM_STAT);
299 /* As for vec_gc_o_reserve_1, but for heap allocated vectors. */
301 static void *
302 vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
303 size_t elt_size, bool exact MEM_STAT_DECL)
305 struct vec_prefix *pfx = (struct vec_prefix *) vec;
306 unsigned alloc = calculate_allocation (pfx, reserve, exact);
308 if (!alloc)
310 if (pfx)
311 vec_heap_free (pfx);
312 return NULL;
315 #ifdef GATHER_STATISTICS
316 if (vec)
317 free_overhead (pfx);
318 #endif
320 vec = xrealloc (vec, vec_offset + alloc * elt_size);
321 ((struct vec_prefix *)vec)->alloc = alloc;
322 if (!pfx)
323 ((struct vec_prefix *)vec)->num = 0;
324 #ifdef GATHER_STATISTICS
325 if (vec)
326 register_overhead ((struct vec_prefix *)vec,
327 vec_offset + alloc * elt_size PASS_MEM_STAT);
328 #endif
330 return vec;
333 /* As for vec_gc_p_reserve, but for heap allocated vectors. */
335 void *
336 vec_heap_p_reserve (void *vec, int reserve MEM_STAT_DECL)
338 return vec_heap_o_reserve_1 (vec, reserve,
339 offsetof (struct vec_prefix, vec),
340 sizeof (void *), false
341 PASS_MEM_STAT);
344 /* As for vec_gc_p_reserve_exact, but for heap allocated vectors. */
346 void *
347 vec_heap_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
349 return vec_heap_o_reserve_1 (vec, reserve,
350 offsetof (struct vec_prefix, vec),
351 sizeof (void *), true
352 PASS_MEM_STAT);
355 /* As for vec_gc_o_reserve, but for heap allocated vectors. */
357 void *
358 vec_heap_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
359 MEM_STAT_DECL)
361 return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
362 PASS_MEM_STAT);
365 /* As for vec_gc_o_reserve_exact, but for heap allocated vectors. */
367 void *
368 vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
369 size_t elt_size MEM_STAT_DECL)
371 return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
372 PASS_MEM_STAT);
375 /* Stack vectors are a little different. VEC_alloc turns into a call
376 to vec_stack_p_reserve_exact1 and passes in space allocated via a
377 call to alloca. We record that pointer so that we know that we
378 shouldn't free it. If the vector is resized, we resize it on the
379 heap. We record the pointers in a vector and search it in LIFO
380 order--i.e., we look for the newest stack vectors first. We don't
381 expect too many stack vectors at any one level, and searching from
382 the end should normally be efficient even if they are used in a
383 recursive function. */
385 typedef void *void_p;
386 DEF_VEC_P(void_p);
387 DEF_VEC_ALLOC_P(void_p,heap);
389 static VEC(void_p,heap) *stack_vecs;
391 /* Allocate a vector which uses alloca for the initial allocation.
392 SPACE is space allocated using alloca, ALLOC is the number of
393 entries allocated. */
395 void *
396 vec_stack_p_reserve_exact_1 (int alloc, void *space)
398 struct vec_prefix *pfx = (struct vec_prefix *) space;
400 VEC_safe_push (void_p, heap, stack_vecs, space);
402 pfx->num = 0;
403 pfx->alloc = alloc;
405 return space;
408 /* Grow a vector allocated using alloca. When this happens, we switch
409 back to heap allocation. We remove the vector from stack_vecs, if
410 it is there, since we no longer need to avoid freeing it. */
412 static void *
413 vec_stack_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
414 size_t elt_size, bool exact MEM_STAT_DECL)
416 bool found;
417 unsigned int ix;
418 void *newvec;
420 found = false;
421 for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
423 if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
425 VEC_unordered_remove (void_p, stack_vecs, ix - 1);
426 found = true;
427 break;
431 if (!found)
433 /* VEC is already on the heap. */
434 return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size,
435 exact PASS_MEM_STAT);
438 /* Move VEC to the heap. */
439 reserve += ((struct vec_prefix *) vec)->num;
440 newvec = vec_heap_o_reserve_1 (NULL, reserve, vec_offset, elt_size,
441 exact PASS_MEM_STAT);
442 if (newvec && vec)
444 ((struct vec_prefix *) newvec)->num = ((struct vec_prefix *) vec)->num;
445 memcpy (((struct vec_prefix *) newvec)->vec,
446 ((struct vec_prefix *) vec)->vec,
447 ((struct vec_prefix *) vec)->num * elt_size);
449 return newvec;
452 /* Grow a vector allocated on the stack. */
454 void *
455 vec_stack_p_reserve (void *vec, int reserve MEM_STAT_DECL)
457 return vec_stack_o_reserve_1 (vec, reserve,
458 offsetof (struct vec_prefix, vec),
459 sizeof (void *), false
460 PASS_MEM_STAT);
463 /* Exact version of vec_stack_p_reserve. */
465 void *
466 vec_stack_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
468 return vec_stack_o_reserve_1 (vec, reserve,
469 offsetof (struct vec_prefix, vec),
470 sizeof (void *), true
471 PASS_MEM_STAT);
474 /* Like vec_stack_p_reserve, but for objects. */
476 void *
477 vec_stack_o_reserve (void *vec, int reserve, size_t vec_offset,
478 size_t elt_size MEM_STAT_DECL)
480 return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
481 PASS_MEM_STAT);
484 /* Like vec_stack_p_reserve_exact, but for objects. */
486 void *
487 vec_stack_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
488 size_t elt_size MEM_STAT_DECL)
490 return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
491 PASS_MEM_STAT);
494 /* Free a vector allocated on the stack. Don't actually free it if we
495 find it in the hash table. */
497 void
498 vec_stack_free (void *vec)
500 unsigned int ix;
502 for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
504 if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
506 VEC_unordered_remove (void_p, stack_vecs, ix - 1);
507 return;
511 /* VEC was not on the list of vecs allocated on the stack, so it
512 must be allocated on the heap. */
513 vec_heap_free (vec);
516 #if ENABLE_CHECKING
517 /* Issue a vector domain error, and then fall over. */
519 void
520 vec_assert_fail (const char *op, const char *struct_name,
521 const char *file, unsigned int line, const char *function)
523 internal_error ("vector %s %s domain error, in %s at %s:%u",
524 struct_name, op, function, trim_filename (file), line);
526 #endif
528 #ifdef GATHER_STATISTICS
529 /* Helper for qsort; sort descriptors by amount of memory consumed. */
530 static int
531 cmp_statistic (const void *loc1, const void *loc2)
533 const struct vec_descriptor *const l1 =
534 *(const struct vec_descriptor *const *) loc1;
535 const struct vec_descriptor *const l2 =
536 *(const struct vec_descriptor *const *) loc2;
537 long diff;
538 diff = l1->allocated - l2->allocated;
539 if (!diff)
540 diff = l1->peak - l2->peak;
541 if (!diff)
542 diff = l1->times - l2->times;
543 return diff > 0 ? 1 : diff < 0 ? -1 : 0;
545 /* Collect array of the descriptors from hashtable. */
546 static struct vec_descriptor **loc_array;
547 static int
548 add_statistics (void **slot, void *b)
550 int *n = (int *)b;
551 loc_array[*n] = (struct vec_descriptor *) *slot;
552 (*n)++;
553 return 1;
556 /* Dump per-site memory statistics. */
557 #endif
558 void
559 dump_vec_loc_statistics (void)
561 #ifdef GATHER_STATISTICS
562 int nentries = 0;
563 char s[4096];
564 size_t allocated = 0;
565 size_t times = 0;
566 int i;
568 loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
569 fprintf (stderr, "Heap vectors:\n");
570 fprintf (stderr, "\n%-48s %10s %10s %10s\n",
571 "source location", "Leak", "Peak", "Times");
572 fprintf (stderr, "-------------------------------------------------------\n");
573 htab_traverse (vec_desc_hash, add_statistics, &nentries);
574 qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
575 for (i = 0; i < nentries; i++)
577 struct vec_descriptor *d = loc_array[i];
578 allocated += d->allocated;
579 times += d->times;
581 for (i = 0; i < nentries; i++)
583 struct vec_descriptor *d = loc_array[i];
584 const char *s1 = d->file;
585 const char *s2;
586 while ((s2 = strstr (s1, "gcc/")))
587 s1 = s2 + 4;
588 sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
589 s[48] = 0;
590 fprintf (stderr, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s,
591 (long)d->allocated,
592 (d->allocated) * 100.0 / allocated,
593 (long)d->peak,
594 (long)d->times,
595 (d->times) * 100.0 / times);
597 fprintf (stderr, "%-48s %10ld %10ld\n",
598 "Total", (long)allocated, (long)times);
599 fprintf (stderr, "\n%-48s %10s %10s %10s\n",
600 "source location", "Leak", "Peak", "Times");
601 fprintf (stderr, "-------------------------------------------------------\n");
602 #endif