new tests
[official-gcc.git] / gcc / vec.c
blob5b472bd1f05d8c36fad0367fc093b6dc72c12eee
1 /* Vector API for GNU compiler.
2 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010
3 Free Software Foundation, Inc.
4 Contributed by Nathan Sidwell <nathan@codesourcery.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 /* This file is compiled twice: once for the generator programs
23 once for the compiler. */
24 #ifdef GENERATOR_FILE
25 #include "bconfig.h"
26 #else
27 #include "config.h"
28 #endif
30 #include "system.h"
31 #include "ggc.h"
32 #include "vec.h"
33 #include "coretypes.h"
34 #include "diagnostic-core.h"
35 #include "hashtab.h"
37 struct vec_prefix
39 unsigned num;
40 unsigned alloc;
41 void *vec[1];
45 #ifdef GATHER_STATISTICS
47 /* Store information about each particular vector. */
48 struct vec_descriptor
50 const char *function;
51 const char *file;
52 int line;
53 size_t allocated;
54 size_t times;
55 size_t peak;
59 /* Hashtable mapping vec addresses to descriptors. */
60 static htab_t vec_desc_hash;
62 /* Hashtable helpers. */
63 static hashval_t
64 hash_descriptor (const void *p)
66 const struct vec_descriptor *const d =
67 (const struct vec_descriptor *) p;
68 return htab_hash_pointer (d->file) + d->line;
70 static int
71 eq_descriptor (const void *p1, const void *p2)
73 const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
74 const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
75 return d->file == l->file && d->function == l->function && d->line == l->line;
78 /* Hashtable converting address of allocated field to loc descriptor. */
79 static htab_t ptr_hash;
80 struct ptr_hash_entry
82 void *ptr;
83 struct vec_descriptor *loc;
84 size_t allocated;
87 /* Hash table helpers functions. */
88 static hashval_t
89 hash_ptr (const void *p)
91 const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
93 return htab_hash_pointer (d->ptr);
96 static int
97 eq_ptr (const void *p1, const void *p2)
99 const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
101 return (p->ptr == p2);
104 /* Return descriptor for given call site, create new one if needed. */
105 static struct vec_descriptor *
106 vec_descriptor (const char *name, int line, const char *function)
108 struct vec_descriptor loc;
109 struct vec_descriptor **slot;
111 loc.file = name;
112 loc.line = line;
113 loc.function = function;
114 if (!vec_desc_hash)
115 vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
117 slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc,
118 INSERT);
119 if (*slot)
120 return *slot;
121 *slot = XCNEW (struct vec_descriptor);
122 (*slot)->file = name;
123 (*slot)->line = line;
124 (*slot)->function = function;
125 (*slot)->allocated = 0;
126 (*slot)->peak = 0;
127 return *slot;
130 /* Account the overhead. */
131 static void
132 register_overhead (struct vec_prefix *ptr, size_t size,
133 const char *name, int line, const char *function)
135 struct vec_descriptor *loc = vec_descriptor (name, line, function);
136 struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
137 PTR *slot;
139 p->ptr = ptr;
140 p->loc = loc;
141 p->allocated = size;
142 if (!ptr_hash)
143 ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
144 slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT);
145 gcc_assert (!*slot);
146 *slot = p;
148 loc->allocated += size;
149 if (loc->peak < loc->allocated)
150 loc->peak += loc->allocated;
151 loc->times++;
154 /* Notice that the pointer has been freed. */
155 static void
156 free_overhead (struct vec_prefix *ptr)
158 PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr),
159 NO_INSERT);
160 struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
161 p->loc->allocated -= p->allocated;
162 htab_clear_slot (ptr_hash, slot);
163 free (p);
166 void
167 vec_heap_free (void *ptr)
169 free_overhead ((struct vec_prefix *)ptr);
170 free (ptr);
172 #endif
174 /* Calculate the new ALLOC value, making sure that RESERVE slots are
175 free. If EXACT grow exactly, otherwise grow exponentially. */
177 static inline unsigned
178 calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact)
180 unsigned alloc = 0;
181 unsigned num = 0;
183 gcc_assert (reserve >= 0);
185 if (pfx)
187 alloc = pfx->alloc;
188 num = pfx->num;
190 else if (!reserve)
191 /* If there's no prefix, and we've not requested anything, then we
192 will create a NULL vector. */
193 return 0;
195 /* We must have run out of room. */
196 gcc_assert (alloc - num < (unsigned) reserve);
198 if (exact)
199 /* Exact size. */
200 alloc = num + reserve;
201 else
203 /* Exponential growth. */
204 if (!alloc)
205 alloc = 4;
206 else if (alloc < 16)
207 /* Double when small. */
208 alloc = alloc * 2;
209 else
210 /* Grow slower when large. */
211 alloc = (alloc * 3 / 2);
213 /* If this is still too small, set it to the right size. */
214 if (alloc < num + reserve)
215 alloc = num + reserve;
217 return alloc;
220 /* Ensure there are at least RESERVE free slots in VEC. If EXACT grow
221 exactly, else grow exponentially. As a special case, if VEC is
222 NULL and RESERVE is 0, no vector will be created. The vector's
223 trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
224 sized elements. */
226 static void *
227 vec_gc_o_reserve_1 (void *vec, int reserve, size_t vec_offset, size_t elt_size,
228 bool exact MEM_STAT_DECL)
230 struct vec_prefix *pfx = (struct vec_prefix *) vec;
231 unsigned alloc = calculate_allocation (pfx, reserve, exact);
233 if (!alloc)
235 if (pfx)
236 ggc_free (pfx);
237 return NULL;
240 vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
241 ((struct vec_prefix *)vec)->alloc = alloc;
242 if (!pfx)
243 ((struct vec_prefix *)vec)->num = 0;
245 return vec;
248 /* Ensure there are at least RESERVE free slots in VEC, growing
249 exponentially. If RESERVE < 0 grow exactly, else grow
250 exponentially. As a special case, if VEC is NULL, and RESERVE is
251 0, no vector will be created. */
253 void *
254 vec_gc_p_reserve (void *vec, int reserve MEM_STAT_DECL)
256 return vec_gc_o_reserve_1 (vec, reserve,
257 offsetof (struct vec_prefix, vec),
258 sizeof (void *), false
259 PASS_MEM_STAT);
262 /* Ensure there are at least RESERVE free slots in VEC, growing
263 exactly. If RESERVE < 0 grow exactly, else grow exponentially. As
264 a special case, if VEC is NULL, and RESERVE is 0, no vector will be
265 created. */
267 void *
268 vec_gc_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
270 return vec_gc_o_reserve_1 (vec, reserve,
271 offsetof (struct vec_prefix, vec),
272 sizeof (void *), true
273 PASS_MEM_STAT);
276 /* As for vec_gc_p_reserve, but for object vectors. The vector's
277 trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
278 sized elements. */
280 void *
281 vec_gc_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
282 MEM_STAT_DECL)
284 return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
285 PASS_MEM_STAT);
288 /* As for vec_gc_p_reserve_exact, but for object vectors. The
289 vector's trailing array is at VEC_OFFSET offset and consists of
290 ELT_SIZE sized elements. */
292 void *
293 vec_gc_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
294 size_t elt_size MEM_STAT_DECL)
296 return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
297 PASS_MEM_STAT);
300 /* As for vec_gc_o_reserve_1, but for heap allocated vectors. */
302 static void *
303 vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
304 size_t elt_size, bool exact MEM_STAT_DECL)
306 struct vec_prefix *pfx = (struct vec_prefix *) vec;
307 unsigned alloc = calculate_allocation (pfx, reserve, exact);
309 if (!alloc)
311 if (pfx)
312 vec_heap_free (pfx);
313 return NULL;
316 #ifdef GATHER_STATISTICS
317 if (vec)
318 free_overhead (pfx);
319 #endif
321 vec = xrealloc (vec, vec_offset + alloc * elt_size);
322 ((struct vec_prefix *)vec)->alloc = alloc;
323 if (!pfx)
324 ((struct vec_prefix *)vec)->num = 0;
325 #ifdef GATHER_STATISTICS
326 if (vec)
327 register_overhead ((struct vec_prefix *)vec,
328 vec_offset + alloc * elt_size PASS_MEM_STAT);
329 #endif
331 return vec;
334 /* As for vec_gc_p_reserve, but for heap allocated vectors. */
336 void *
337 vec_heap_p_reserve (void *vec, int reserve MEM_STAT_DECL)
339 return vec_heap_o_reserve_1 (vec, reserve,
340 offsetof (struct vec_prefix, vec),
341 sizeof (void *), false
342 PASS_MEM_STAT);
345 /* As for vec_gc_p_reserve_exact, but for heap allocated vectors. */
347 void *
348 vec_heap_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
350 return vec_heap_o_reserve_1 (vec, reserve,
351 offsetof (struct vec_prefix, vec),
352 sizeof (void *), true
353 PASS_MEM_STAT);
356 /* As for vec_gc_o_reserve, but for heap allocated vectors. */
358 void *
359 vec_heap_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
360 MEM_STAT_DECL)
362 return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
363 PASS_MEM_STAT);
366 /* As for vec_gc_o_reserve_exact, but for heap allocated vectors. */
368 void *
369 vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
370 size_t elt_size MEM_STAT_DECL)
372 return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
373 PASS_MEM_STAT);
376 /* Stack vectors are a little different. VEC_alloc turns into a call
377 to vec_stack_p_reserve_exact1 and passes in space allocated via a
378 call to alloca. We record that pointer so that we know that we
379 shouldn't free it. If the vector is resized, we resize it on the
380 heap. We record the pointers in a vector and search it in LIFO
381 order--i.e., we look for the newest stack vectors first. We don't
382 expect too many stack vectors at any one level, and searching from
383 the end should normally be efficient even if they are used in a
384 recursive function. */
386 typedef void *void_p;
387 DEF_VEC_P(void_p);
388 DEF_VEC_ALLOC_P(void_p,heap);
390 static VEC(void_p,heap) *stack_vecs;
392 /* Allocate a vector which uses alloca for the initial allocation.
393 SPACE is space allocated using alloca, ALLOC is the number of
394 entries allocated. */
396 void *
397 vec_stack_p_reserve_exact_1 (int alloc, void *space)
399 struct vec_prefix *pfx = (struct vec_prefix *) space;
401 VEC_safe_push (void_p, heap, stack_vecs, space);
403 pfx->num = 0;
404 pfx->alloc = alloc;
406 return space;
409 /* Grow a vector allocated using alloca. When this happens, we switch
410 back to heap allocation. We remove the vector from stack_vecs, if
411 it is there, since we no longer need to avoid freeing it. */
413 static void *
414 vec_stack_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
415 size_t elt_size, bool exact MEM_STAT_DECL)
417 bool found;
418 unsigned int ix;
419 void *newvec;
421 found = false;
422 for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
424 if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
426 VEC_unordered_remove (void_p, stack_vecs, ix - 1);
427 found = true;
428 break;
432 if (!found)
434 /* VEC is already on the heap. */
435 return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size,
436 exact PASS_MEM_STAT);
439 /* Move VEC to the heap. */
440 reserve += ((struct vec_prefix *) vec)->num;
441 newvec = vec_heap_o_reserve_1 (NULL, reserve, vec_offset, elt_size,
442 exact PASS_MEM_STAT);
443 if (newvec && vec)
445 ((struct vec_prefix *) newvec)->num = ((struct vec_prefix *) vec)->num;
446 memcpy (((struct vec_prefix *) newvec)->vec,
447 ((struct vec_prefix *) vec)->vec,
448 ((struct vec_prefix *) vec)->num * elt_size);
450 return newvec;
453 /* Grow a vector allocated on the stack. */
455 void *
456 vec_stack_p_reserve (void *vec, int reserve MEM_STAT_DECL)
458 return vec_stack_o_reserve_1 (vec, reserve,
459 offsetof (struct vec_prefix, vec),
460 sizeof (void *), false
461 PASS_MEM_STAT);
464 /* Exact version of vec_stack_p_reserve. */
466 void *
467 vec_stack_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
469 return vec_stack_o_reserve_1 (vec, reserve,
470 offsetof (struct vec_prefix, vec),
471 sizeof (void *), true
472 PASS_MEM_STAT);
475 /* Like vec_stack_p_reserve, but for objects. */
477 void *
478 vec_stack_o_reserve (void *vec, int reserve, size_t vec_offset,
479 size_t elt_size MEM_STAT_DECL)
481 return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
482 PASS_MEM_STAT);
485 /* Like vec_stack_p_reserve_exact, but for objects. */
487 void *
488 vec_stack_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
489 size_t elt_size MEM_STAT_DECL)
491 return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
492 PASS_MEM_STAT);
495 /* Free a vector allocated on the stack. Don't actually free it if we
496 find it in the hash table. */
498 void
499 vec_stack_free (void *vec)
501 unsigned int ix;
503 for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
505 if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
507 VEC_unordered_remove (void_p, stack_vecs, ix - 1);
508 return;
512 /* VEC was not on the list of vecs allocated on the stack, so it
513 must be allocated on the heap. */
514 vec_heap_free (vec);
517 #if ENABLE_CHECKING
518 /* Issue a vector domain error, and then fall over. */
520 void
521 vec_assert_fail (const char *op, const char *struct_name,
522 const char *file, unsigned int line, const char *function)
524 internal_error ("vector %s %s domain error, in %s at %s:%u",
525 struct_name, op, function, trim_filename (file), line);
527 #endif
529 #ifdef GATHER_STATISTICS
530 /* Helper for qsort; sort descriptors by amount of memory consumed. */
531 static int
532 cmp_statistic (const void *loc1, const void *loc2)
534 const struct vec_descriptor *const l1 =
535 *(const struct vec_descriptor *const *) loc1;
536 const struct vec_descriptor *const l2 =
537 *(const struct vec_descriptor *const *) loc2;
538 long diff;
539 diff = l1->allocated - l2->allocated;
540 if (!diff)
541 diff = l1->peak - l2->peak;
542 if (!diff)
543 diff = l1->times - l2->times;
544 return diff > 0 ? 1 : diff < 0 ? -1 : 0;
546 /* Collect array of the descriptors from hashtable. */
547 static struct vec_descriptor **loc_array;
548 static int
549 add_statistics (void **slot, void *b)
551 int *n = (int *)b;
552 loc_array[*n] = (struct vec_descriptor *) *slot;
553 (*n)++;
554 return 1;
557 /* Dump per-site memory statistics. */
558 #endif
559 void
560 dump_vec_loc_statistics (void)
562 #ifdef GATHER_STATISTICS
563 int nentries = 0;
564 char s[4096];
565 size_t allocated = 0;
566 size_t times = 0;
567 int i;
569 loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
570 fprintf (stderr, "Heap vectors:\n");
571 fprintf (stderr, "\n%-48s %10s %10s %10s\n",
572 "source location", "Leak", "Peak", "Times");
573 fprintf (stderr, "-------------------------------------------------------\n");
574 htab_traverse (vec_desc_hash, add_statistics, &nentries);
575 qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
576 for (i = 0; i < nentries; i++)
578 struct vec_descriptor *d = loc_array[i];
579 allocated += d->allocated;
580 times += d->times;
582 for (i = 0; i < nentries; i++)
584 struct vec_descriptor *d = loc_array[i];
585 const char *s1 = d->file;
586 const char *s2;
587 while ((s2 = strstr (s1, "gcc/")))
588 s1 = s2 + 4;
589 sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
590 s[48] = 0;
591 fprintf (stderr, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s,
592 (long)d->allocated,
593 (d->allocated) * 100.0 / allocated,
594 (long)d->peak,
595 (long)d->times,
596 (d->times) * 100.0 / times);
598 fprintf (stderr, "%-48s %10ld %10ld\n",
599 "Total", (long)allocated, (long)times);
600 fprintf (stderr, "\n%-48s %10s %10s %10s\n",
601 "source location", "Leak", "Peak", "Times");
602 fprintf (stderr, "-------------------------------------------------------\n");
603 #endif