1 /* Vector API for GNU compiler.
2 Copyright (C) 2004-2017 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
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
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. */
31 #include "coretypes.h"
32 #include "hash-table.h"
38 #include "diagnostic-core.h"
41 /* vNULL is an empty type with a template cast operation that returns
42 a zero-initialized vec<T, A, L> instance. Use this when you want
43 to assign nil values to new vec instances or pass a nil vector as
44 a function call argument.
46 We use this technique because vec<T, A, L> must be PODs (they are
47 stored in unions and passed in vararg functions), this means that
48 they cannot have ctors/dtors. */
51 /* Vector memory usage. */
52 struct vec_usage
: public mem_usage
54 /* Default constructor. */
55 vec_usage (): m_items (0), m_items_peak (0) {}
58 vec_usage (size_t allocated
, size_t times
, size_t peak
,
59 size_t items
, size_t items_peak
)
60 : mem_usage (allocated
, times
, peak
),
61 m_items (items
), m_items_peak (items_peak
) {}
63 /* Comparison operator. */
65 operator< (const vec_usage
&second
) const
67 return (m_allocated
== second
.m_allocated
?
68 (m_peak
== second
.m_peak
? m_times
< second
.m_times
69 : m_peak
< second
.m_peak
) : m_allocated
< second
.m_allocated
);
72 /* Sum the usage with SECOND usage. */
74 operator+ (const vec_usage
&second
)
76 return vec_usage (m_allocated
+ second
.m_allocated
,
77 m_times
+ second
.m_times
,
78 m_peak
+ second
.m_peak
,
79 m_items
+ second
.m_items
,
80 m_items_peak
+ second
.m_items_peak
);
83 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
85 dump (mem_location
*loc
, mem_usage
&total
) const
88 sprintf (s
, "%s:%i (%s)", loc
->get_trimmed_filename (),
89 loc
->m_line
, loc
->m_function
);
93 fprintf (stderr
, "%-48s %10li:%4.1f%%%10li%10li:%4.1f%%%11li%11li\n", s
,
94 (long)m_allocated
, m_allocated
* 100.0 / total
.m_allocated
,
95 (long)m_peak
, (long)m_times
, m_times
* 100.0 / total
.m_times
,
96 (long)m_items
, (long)m_items_peak
);
104 fprintf (stderr
, "%s%55li%25li%17li\n", "Total", (long)m_allocated
,
105 (long)m_times
, (long)m_items
);
109 /* Dump header with NAME. */
111 dump_header (const char *name
)
113 fprintf (stderr
, "%-48s %11s%15s%10s%17s%11s\n", name
, "Leak", "Peak",
114 "Times", "Leak items", "Peak items");
118 /* Compare wrapper used by qsort method. */
120 compare (const void *first
, const void *second
)
122 typedef std::pair
<mem_location
*, vec_usage
*> mem_pair_t
;
124 const mem_pair_t f
= *(const mem_pair_t
*)first
;
125 const mem_pair_t s
= *(const mem_pair_t
*)second
;
127 return (*f
.second
) < (*s
.second
);
130 /* Current number of items allocated. */
132 /* Peak value of number of allocated items. */
136 /* Vector memory description. */
137 static mem_alloc_description
<vec_usage
> vec_mem_desc
;
139 /* Account the overhead. */
142 vec_prefix::register_overhead (void *ptr
, size_t size
, size_t elements
145 vec_mem_desc
.register_descriptor (ptr
, VEC_ORIGIN
, false
146 FINAL_PASS_MEM_STAT
);
147 vec_usage
*usage
= vec_mem_desc
.register_instance_overhead (size
, ptr
);
148 usage
->m_items
+= elements
;
149 if (usage
->m_items_peak
< usage
->m_items
)
150 usage
->m_items_peak
= usage
->m_items
;
153 /* Notice that the memory allocated for the vector has been freed. */
156 vec_prefix::release_overhead (void *ptr
, size_t size
, bool in_dtor
159 if (!vec_mem_desc
.contains_descriptor_for_instance (ptr
))
160 vec_mem_desc
.register_descriptor (ptr
, VEC_ORIGIN
,
161 false FINAL_PASS_MEM_STAT
);
162 vec_mem_desc
.release_instance_overhead (ptr
, size
, in_dtor
);
166 /* Calculate the number of slots to reserve a vector, making sure that
167 it is of at least DESIRED size by growing ALLOC exponentially. */
170 vec_prefix::calculate_allocation_1 (unsigned alloc
, unsigned desired
)
172 /* We must have run out of room. */
173 gcc_assert (alloc
< desired
);
175 /* Exponential growth. */
179 /* Double when small. */
182 /* Grow slower when large. */
183 alloc
= (alloc
* 3 / 2);
185 /* If this is still too small, set it to the right size. */
191 /* Dump per-site memory statistics. */
194 dump_vec_loc_statistics (void)
196 vec_mem_desc
.dump (VEC_ORIGIN
);
200 /* Report qsort comparator CMP consistency check failure with P1, P2, P3 as
202 ATTRIBUTE_NORETURN ATTRIBUTE_COLD
204 qsort_chk_error (const void *p1
, const void *p2
, const void *p3
,
205 int (*cmp
) (const void *, const void *))
209 int r1
= cmp (p1
, p2
), r2
= cmp (p2
, p1
);
210 error ("qsort comparator not anti-commutative: %d, %d", r1
, r2
);
214 int r
= cmp (p1
, p3
);
215 error ("qsort comparator non-negative on sorted output: %d", r
);
219 int r1
= cmp (p1
, p2
), r2
= cmp (p2
, p3
), r3
= cmp (p1
, p3
);
220 error ("qsort comparator not transitive: %d, %d, %d", r1
, r2
, r3
);
222 internal_error ("qsort checking failed");
225 /* Wrapper around qsort with checking that CMP is consistent on given input.
227 Strictly speaking, passing invalid (non-transitive, non-anti-commutative)
228 comparators to libc qsort can result in undefined behavior. Therefore we
229 should ideally perform consistency checks prior to invoking qsort, but in
230 order to do that optimally we'd need to sort the array ourselves beforehand
231 with a sorting routine known to be "safe". Instead, we expect that most
232 implementations in practice will still produce some permutation of input
233 array even for invalid comparators, which enables us to perform checks on
236 qsort_chk (void *base
, size_t n
, size_t size
,
237 int (*cmp
)(const void *, const void *))
239 (qsort
) (base
, n
, size
, cmp
);
243 /* Limit overall time complexity to O(n log n). */
244 #define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n))
246 #define ELT(i) ((const char *) base + (i) * size)
247 #define CMP(i, j) cmp (ELT (i), ELT (j))
248 #define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp)
249 #define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp)
251 /* This outer loop iterates over maximum spans [i1, i2) such that
252 elements within each span compare equal to each other. */
253 for (i1
= 0; i1
< n
; i1
= i2
)
255 /* Position i2 one past last element that compares equal to i1'th. */
256 for (i2
= i1
+ 1; i2
< n
; i2
++)
259 else if (CMP (i2
, i1
))
260 return ERR2 (i1
, i2
);
261 size_t lim1
= LIM (i2
- i1
), lim2
= LIM (n
- i2
);
262 /* Verify that other pairs within current span compare equal. */
263 for (i
= i1
+ 1; i
+ 1 < i2
; i
++)
264 for (j
= i
+ 1; j
< i1
+ lim1
; j
++)
266 return ERR3 (i
, i1
, j
);
269 /* Verify that elements within this span compare less than
270 elements beyond the span. */
271 for (i
= i1
; i
< i2
; i
++)
272 for (j
= i2
; j
< i2
+ lim2
; j
++)
274 return ERR3 (i
, i1
, j
);
275 else if (CMP (j
, i
) <= 0)
284 #endif /* #if CHECKING_P */
286 #ifndef GENERATOR_FILE
293 /* Call V.safe_push for all ints from START up to, but not including LIMIT.
294 Helper function for selftests. */
297 safe_push_range (vec
<int>&v
, int start
, int limit
)
299 for (int i
= start
; i
< limit
; i
++)
303 /* Verify that vec::quick_push works correctly. */
309 ASSERT_EQ (0, v
.length ());
311 ASSERT_EQ (0, v
.length ());
312 ASSERT_TRUE (v
.space (3));
316 ASSERT_EQ (3, v
.length ());
322 /* Verify that vec::safe_push works correctly. */
328 ASSERT_EQ (0, v
.length ());
332 ASSERT_EQ (3, v
.length ());
338 /* Verify that vec::truncate works correctly. */
344 ASSERT_EQ (0, v
.length ());
345 safe_push_range (v
, 0, 10);
346 ASSERT_EQ (10, v
.length ());
349 ASSERT_EQ (5, v
.length ());
352 /* Verify that vec::safe_grow_cleared works correctly. */
355 test_safe_grow_cleared ()
358 ASSERT_EQ (0, v
.length ());
359 v
.safe_grow_cleared (50);
360 ASSERT_EQ (50, v
.length ());
362 ASSERT_EQ (0, v
[49]);
365 /* Verify that vec::pop works correctly. */
371 safe_push_range (v
, 5, 20);
372 ASSERT_EQ (15, v
.length ());
375 ASSERT_EQ (19, last
);
376 ASSERT_EQ (14, v
.length ());
379 /* Verify that vec::safe_insert works correctly. */
385 safe_push_range (v
, 0, 10);
386 v
.safe_insert (5, 42);
388 ASSERT_EQ (42, v
[5]);
390 ASSERT_EQ (11, v
.length ());
393 /* Verify that vec::ordered_remove works correctly. */
396 test_ordered_remove ()
399 safe_push_range (v
, 0, 10);
400 v
.ordered_remove (5);
403 ASSERT_EQ (9, v
.length ());
406 /* Verify that vec::unordered_remove works correctly. */
409 test_unordered_remove ()
412 safe_push_range (v
, 0, 10);
413 v
.unordered_remove (5);
414 ASSERT_EQ (9, v
.length ());
417 /* Verify that vec::block_remove works correctly. */
423 safe_push_range (v
, 0, 10);
424 v
.block_remove (5, 3);
429 ASSERT_EQ (7, v
.length ());
432 /* Comparator for use by test_qsort. */
435 reverse_cmp (const void *p_i
, const void *p_j
)
437 return *(const int *)p_j
- *(const int *)p_i
;
440 /* Verify that vec::qsort works correctly. */
446 safe_push_range (v
, 0, 10);
447 v
.qsort (reverse_cmp
);
452 ASSERT_EQ (10, v
.length ());
455 /* Run all of the selftests within this file. */
463 test_safe_grow_cleared ();
466 test_ordered_remove ();
467 test_unordered_remove ();
468 test_block_remove ();
472 } // namespace selftest
474 #endif /* #if CHECKING_P */
475 #endif /* #ifndef GENERATOR_FILE */