xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/vec.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
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>
4 
5 This file is part of GCC.
6 
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.
11 
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.
16 
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/>.  */
20 
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
28 
29 #include "system.h"
30 #include "ggc.h"
31 #include "vec.h"
32 #include "coretypes.h"
33 #include "toplev.h"
34 #include "hashtab.h"
35 
36 struct vec_prefix
37 {
38   unsigned num;
39   unsigned alloc;
40   void *vec[1];
41 };
42 
43 
44 #ifdef GATHER_STATISTICS
45 
46 /* Store information about each particular vector.  */
47 struct vec_descriptor
48 {
49   const char *function;
50   const char *file;
51   int line;
52   size_t allocated;
53   size_t times;
54   size_t peak;
55 };
56 
57 
58 /* Hashtable mapping vec addresses to descriptors.  */
59 static htab_t vec_desc_hash;
60 
61 /* Hashtable helpers.  */
62 static hashval_t
63 hash_descriptor (const void *p)
64 {
65   const struct vec_descriptor *const d =
66     (const struct vec_descriptor *) p;
67   return htab_hash_pointer (d->file) + d->line;
68 }
69 static int
70 eq_descriptor (const void *p1, const void *p2)
71 {
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;
75 }
76 
77 /* Hashtable converting address of allocated field to loc descriptor.  */
78 static htab_t ptr_hash;
79 struct ptr_hash_entry
80 {
81   void *ptr;
82   struct vec_descriptor *loc;
83   size_t allocated;
84 };
85 
86 /* Hash table helpers functions.  */
87 static hashval_t
88 hash_ptr (const void *p)
89 {
90   const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
91 
92   return htab_hash_pointer (d->ptr);
93 }
94 
95 static int
96 eq_ptr (const void *p1, const void *p2)
97 {
98   const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
99 
100   return (p->ptr == p2);
101 }
102 
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)
106 {
107   struct vec_descriptor loc;
108   struct vec_descriptor **slot;
109 
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);
115 
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;
127 }
128 
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)
133 {
134   struct vec_descriptor *loc = vec_descriptor (name, line, function);
135   struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
136   PTR *slot;
137 
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;
146 
147   loc->allocated += size;
148   if (loc->peak < loc->allocated)
149     loc->peak += loc->allocated;
150   loc->times++;
151 }
152 
153 /* Notice that the pointer has been freed.  */
154 static void
155 free_overhead (struct vec_prefix *ptr)
156 {
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);
163 }
164 
165 void
166 vec_heap_free (void *ptr)
167 {
168   free_overhead ((struct vec_prefix *)ptr);
169   free (ptr);
170 }
171 #endif
172 
173 /* Calculate the new ALLOC value, making sure that RESERVE slots are
174    free.  If EXACT grow exactly, otherwise grow exponentially.  */
175 
176 static inline unsigned
177 calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact)
178 {
179   unsigned alloc = 0;
180   unsigned num = 0;
181 
182   gcc_assert (reserve >= 0);
183 
184   if (pfx)
185     {
186       alloc = pfx->alloc;
187       num = pfx->num;
188     }
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;
193 
194   /* We must have run out of room.  */
195   gcc_assert (alloc - num < (unsigned) reserve);
196 
197   if (exact)
198     /* Exact size.  */
199     alloc = num + reserve;
200   else
201     {
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);
211 
212       /* If this is still too small, set it to the right size. */
213       if (alloc < num + reserve)
214 	alloc = num + reserve;
215     }
216   return alloc;
217 }
218 
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.  */
224 
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)
228 {
229   struct vec_prefix *pfx = (struct vec_prefix *) vec;
230   unsigned alloc = calculate_allocation (pfx, reserve, exact);
231 
232   if (!alloc)
233     {
234       if (pfx)
235         ggc_free (pfx);
236       return NULL;
237     }
238 
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;
243 
244   return vec;
245 }
246 
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. */
251 
252 void *
253 vec_gc_p_reserve (void *vec, int reserve MEM_STAT_DECL)
254 {
255   return vec_gc_o_reserve_1 (vec, reserve,
256 			     offsetof (struct vec_prefix, vec),
257 			     sizeof (void *), false
258 			     PASS_MEM_STAT);
259 }
260 
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. */
265 
266 void *
267 vec_gc_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
268 {
269   return vec_gc_o_reserve_1 (vec, reserve,
270 			     offsetof (struct vec_prefix, vec),
271 			     sizeof (void *), true
272 			     PASS_MEM_STAT);
273 }
274 
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.  */
278 
279 void *
280 vec_gc_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
281 		  MEM_STAT_DECL)
282 {
283   return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
284 			     PASS_MEM_STAT);
285 }
286 
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.  */
290 
291 void *
292 vec_gc_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
293 			size_t elt_size MEM_STAT_DECL)
294 {
295   return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
296 			     PASS_MEM_STAT);
297 }
298 
299 /* As for vec_gc_o_reserve_1, but for heap allocated vectors.  */
300 
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)
304 {
305   struct vec_prefix *pfx = (struct vec_prefix *) vec;
306   unsigned alloc = calculate_allocation (pfx, reserve, exact);
307 
308   if (!alloc)
309     {
310       if (pfx)
311         vec_heap_free (pfx);
312       return NULL;
313     }
314 
315 #ifdef GATHER_STATISTICS
316   if (vec)
317     free_overhead (pfx);
318 #endif
319 
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
329 
330   return vec;
331 }
332 
333 /* As for vec_gc_p_reserve, but for heap allocated vectors.  */
334 
335 void *
336 vec_heap_p_reserve (void *vec, int reserve MEM_STAT_DECL)
337 {
338   return vec_heap_o_reserve_1 (vec, reserve,
339 			       offsetof (struct vec_prefix, vec),
340 			       sizeof (void *), false
341 			       PASS_MEM_STAT);
342 }
343 
344 /* As for vec_gc_p_reserve_exact, but for heap allocated vectors.  */
345 
346 void *
347 vec_heap_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
348 {
349   return vec_heap_o_reserve_1 (vec, reserve,
350 			       offsetof (struct vec_prefix, vec),
351 			       sizeof (void *), true
352 			       PASS_MEM_STAT);
353 }
354 
355 /* As for vec_gc_o_reserve, but for heap allocated vectors.  */
356 
357 void *
358 vec_heap_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
359 		    MEM_STAT_DECL)
360 {
361   return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
362 			       PASS_MEM_STAT);
363 }
364 
365 /* As for vec_gc_o_reserve_exact, but for heap allocated vectors.  */
366 
367 void *
368 vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
369 			  size_t elt_size MEM_STAT_DECL)
370 {
371   return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
372 			       PASS_MEM_STAT);
373 }
374 
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.  */
384 
385 typedef void *void_p;
386 DEF_VEC_P(void_p);
387 DEF_VEC_ALLOC_P(void_p,heap);
388 
389 static VEC(void_p,heap) *stack_vecs;
390 
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.  */
394 
395 void *
396 vec_stack_p_reserve_exact_1 (int alloc, void *space)
397 {
398   struct vec_prefix *pfx = (struct vec_prefix *) space;
399 
400   VEC_safe_push (void_p, heap, stack_vecs, space);
401 
402   pfx->num = 0;
403   pfx->alloc = alloc;
404 
405   return space;
406 }
407 
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.  */
411 
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)
415 {
416   bool found;
417   unsigned int ix;
418   void *newvec;
419 
420   found = false;
421   for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
422     {
423       if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
424 	{
425 	  VEC_unordered_remove (void_p, stack_vecs, ix - 1);
426 	  found = true;
427 	  break;
428 	}
429     }
430 
431   if (!found)
432     {
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);
436     }
437 
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)
443     {
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);
448     }
449   return newvec;
450 }
451 
452 /* Grow a vector allocated on the stack.  */
453 
454 void *
455 vec_stack_p_reserve (void *vec, int reserve MEM_STAT_DECL)
456 {
457   return vec_stack_o_reserve_1 (vec, reserve,
458 				offsetof (struct vec_prefix, vec),
459 				sizeof (void *), false
460 				PASS_MEM_STAT);
461 }
462 
463 /* Exact version of vec_stack_p_reserve.  */
464 
465 void *
466 vec_stack_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
467 {
468   return vec_stack_o_reserve_1 (vec, reserve,
469 				offsetof (struct vec_prefix, vec),
470 				sizeof (void *), true
471 				PASS_MEM_STAT);
472 }
473 
474 /* Like vec_stack_p_reserve, but for objects.  */
475 
476 void *
477 vec_stack_o_reserve (void *vec, int reserve, size_t vec_offset,
478 		     size_t elt_size MEM_STAT_DECL)
479 {
480   return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
481 				PASS_MEM_STAT);
482 }
483 
484 /* Like vec_stack_p_reserve_exact, but for objects.  */
485 
486 void *
487 vec_stack_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
488 			    size_t elt_size MEM_STAT_DECL)
489 {
490   return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
491 				PASS_MEM_STAT);
492 }
493 
494 /* Free a vector allocated on the stack.  Don't actually free it if we
495    find it in the hash table.  */
496 
497 void
498 vec_stack_free (void *vec)
499 {
500   unsigned int ix;
501 
502   for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
503     {
504       if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
505 	{
506 	  VEC_unordered_remove (void_p, stack_vecs, ix - 1);
507 	  return;
508 	}
509     }
510 
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);
514 }
515 
516 #if ENABLE_CHECKING
517 /* Issue a vector domain error, and then fall over.  */
518 
519 void
520 vec_assert_fail (const char *op, const char *struct_name,
521 		 const char *file, unsigned int line, const char *function)
522 {
523   internal_error ("vector %s %s domain error, in %s at %s:%u",
524 		  struct_name, op, function, trim_filename (file), line);
525 }
526 #endif
527 
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)
532 {
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;
544 }
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)
549 {
550   int *n = (int *)b;
551   loc_array[*n] = (struct vec_descriptor *) *slot;
552   (*n)++;
553   return 1;
554 }
555 
556 /* Dump per-site memory statistics.  */
557 #endif
558 void
559 dump_vec_loc_statistics (void)
560 {
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;
567 
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++)
576     {
577       struct vec_descriptor *d = loc_array[i];
578       allocated += d->allocated;
579       times += d->times;
580     }
581   for (i = 0; i < nentries; i++)
582     {
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);
596     }
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
603 }
604