vectorizer cost model enhancement
[official-gcc.git] / gcc / vec.c
blob979ecc81ba5687553ee13b936b4bb3de16227cf1
1 /* Vector API for GNU compiler.
2 Copyright (C) 2004-2013 Free Software Foundation, Inc.
3 Contributed by Nathan Sidwell <nathan@codesourcery.com>
4 Re-implemented in C++ by Diego Novillo <dnovillo@google.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 "coretypes.h"
32 #include "ggc.h"
33 #include "vec.h"
34 #include "diagnostic-core.h"
35 #include "hashtab.h"
37 /* vNULL is an empty type with a template cast operation that returns
38 a zero-initialized vec<T, A, L> instance. Use this when you want
39 to assign nil values to new vec instances or pass a nil vector as
40 a function call argument.
42 We use this technique because vec<T, A, L> must be PODs (they are
43 stored in unions and passed in vararg functions), this means that
44 they cannot have ctors/dtors. */
45 vnull vNULL;
48 /* Store information about each particular vector. */
49 struct vec_descriptor
51 const char *function;
52 const char *file;
53 int line;
54 size_t allocated;
55 size_t times;
56 size_t peak;
60 /* Hashtable mapping vec addresses to descriptors. */
61 static htab_t vec_desc_hash;
63 /* Hashtable helpers. */
64 static hashval_t
65 hash_descriptor (const void *p)
67 const struct vec_descriptor *const d =
68 (const struct vec_descriptor *) p;
69 return htab_hash_pointer (d->file) + d->line;
71 static int
72 eq_descriptor (const void *p1, const void *p2)
74 const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
75 const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
76 return d->file == l->file && d->function == l->function && d->line == l->line;
79 /* Hashtable converting address of allocated field to loc descriptor. */
80 static htab_t ptr_hash;
81 struct ptr_hash_entry
83 void *ptr;
84 struct vec_descriptor *loc;
85 size_t allocated;
88 /* Hash table helpers functions. */
89 static hashval_t
90 hash_ptr (const void *p)
92 const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
94 return htab_hash_pointer (d->ptr);
97 static int
98 eq_ptr (const void *p1, const void *p2)
100 const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
102 return (p->ptr == p2);
105 /* Return descriptor for given call site, create new one if needed. */
106 static struct vec_descriptor *
107 vec_descriptor (const char *name, int line, const char *function)
109 struct vec_descriptor loc;
110 struct vec_descriptor **slot;
112 loc.file = name;
113 loc.line = line;
114 loc.function = function;
115 if (!vec_desc_hash)
116 vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
118 slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc,
119 INSERT);
120 if (*slot)
121 return *slot;
122 *slot = XCNEW (struct vec_descriptor);
123 (*slot)->file = name;
124 (*slot)->line = line;
125 (*slot)->function = function;
126 (*slot)->allocated = 0;
127 (*slot)->peak = 0;
128 return *slot;
131 /* Account the overhead. */
133 void
134 vec_prefix::register_overhead (size_t size, const char *name, int line,
135 const char *function)
137 struct vec_descriptor *loc = vec_descriptor (name, line, function);
138 struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
139 PTR *slot;
141 p->ptr = this;
142 p->loc = loc;
143 p->allocated = size;
144 if (!ptr_hash)
145 ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
146 slot = htab_find_slot_with_hash (ptr_hash, this, htab_hash_pointer (this),
147 INSERT);
148 gcc_assert (!*slot);
149 *slot = p;
151 loc->allocated += size;
152 if (loc->peak < loc->allocated)
153 loc->peak += loc->allocated;
154 loc->times++;
158 /* Notice that the memory allocated for the vector has been freed. */
160 void
161 vec_prefix::release_overhead (void)
163 PTR *slot = htab_find_slot_with_hash (ptr_hash, this,
164 htab_hash_pointer (this),
165 NO_INSERT);
166 struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
167 p->loc->allocated -= p->allocated;
168 htab_clear_slot (ptr_hash, slot);
169 ::free (p);
173 /* Calculate the number of slots to reserve a vector, making sure that
174 RESERVE slots are free. If EXACT grow exactly, otherwise grow
175 exponentially. PFX is the control data for the vector. */
177 unsigned
178 vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve,
179 bool exact)
181 unsigned alloc = 0;
182 unsigned num = 0;
184 if (pfx)
186 alloc = pfx->alloc_;
187 num = pfx->num_;
189 else if (!reserve)
190 /* If there's no vector, 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 < 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;
220 /* Stack vectors are a little different. VEC_alloc turns into a call
221 to vec<T, A>::stack_reserve and passes in space allocated via a
222 call to alloca. We record that pointer so that we know that we
223 shouldn't free it. If the vector is resized, we resize it on the
224 heap. We record the pointers in a vector and search it in LIFO
225 order--i.e., we look for the newest stack vectors first. We don't
226 expect too many stack vectors at any one level, and searching from
227 the end should normally be efficient even if they are used in a
228 recursive function. */
230 static vec<void *> stack_vecs;
232 /* Add a stack vector to STACK_VECS. */
234 void
235 register_stack_vec (void *vec)
237 stack_vecs.safe_push (vec);
241 /* If VEC is registered in STACK_VECS, return its index.
242 Otherwise, return -1. */
245 stack_vec_register_index (void *vec)
247 for (unsigned ix = stack_vecs.length (); ix > 0; --ix)
248 if (stack_vecs[ix - 1] == vec)
249 return static_cast<int> (ix - 1);
250 return -1;
254 /* Remove vector at slot IX from the list of registered stack vectors. */
256 void
257 unregister_stack_vec (unsigned ix)
259 stack_vecs.unordered_remove (ix);
263 /* Helper for qsort; sort descriptors by amount of memory consumed. */
265 static int
266 cmp_statistic (const void *loc1, const void *loc2)
268 const struct vec_descriptor *const l1 =
269 *(const struct vec_descriptor *const *) loc1;
270 const struct vec_descriptor *const l2 =
271 *(const struct vec_descriptor *const *) loc2;
272 long diff;
273 diff = l1->allocated - l2->allocated;
274 if (!diff)
275 diff = l1->peak - l2->peak;
276 if (!diff)
277 diff = l1->times - l2->times;
278 return diff > 0 ? 1 : diff < 0 ? -1 : 0;
282 /* Collect array of the descriptors from hashtable. */
284 static struct vec_descriptor **loc_array;
285 static int
286 add_statistics (void **slot, void *b)
288 int *n = (int *)b;
289 loc_array[*n] = (struct vec_descriptor *) *slot;
290 (*n)++;
291 return 1;
294 /* Dump per-site memory statistics. */
296 void
297 dump_vec_loc_statistics (void)
299 int nentries = 0;
300 char s[4096];
301 size_t allocated = 0;
302 size_t times = 0;
303 int i;
305 if (! GATHER_STATISTICS)
306 return;
308 loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
309 fprintf (stderr, "Heap vectors:\n");
310 fprintf (stderr, "\n%-48s %10s %10s %10s\n",
311 "source location", "Leak", "Peak", "Times");
312 fprintf (stderr, "-------------------------------------------------------\n");
313 htab_traverse (vec_desc_hash, add_statistics, &nentries);
314 qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
315 for (i = 0; i < nentries; i++)
317 struct vec_descriptor *d = loc_array[i];
318 allocated += d->allocated;
319 times += d->times;
321 for (i = 0; i < nentries; i++)
323 struct vec_descriptor *d = loc_array[i];
324 const char *s1 = d->file;
325 const char *s2;
326 while ((s2 = strstr (s1, "gcc/")))
327 s1 = s2 + 4;
328 sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
329 s[48] = 0;
330 fprintf (stderr, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s,
331 (long)d->allocated,
332 (d->allocated) * 100.0 / allocated,
333 (long)d->peak,
334 (long)d->times,
335 (d->times) * 100.0 / times);
337 fprintf (stderr, "%-48s %10ld %10ld\n",
338 "Total", (long)allocated, (long)times);
339 fprintf (stderr, "\n%-48s %10s %10s %10s\n",
340 "source location", "Leak", "Peak", "Times");
341 fprintf (stderr, "-------------------------------------------------------\n");