1 /* Vector API for GNU compiler.
2 Copyright (C) 2004-2018 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 /* Sum the usage with SECOND usage. */
65 operator+ (const vec_usage
&second
)
67 return vec_usage (m_allocated
+ second
.m_allocated
,
68 m_times
+ second
.m_times
,
69 m_peak
+ second
.m_peak
,
70 m_items
+ second
.m_items
,
71 m_items_peak
+ second
.m_items_peak
);
74 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
76 dump (mem_location
*loc
, mem_usage
&total
) const
79 sprintf (s
, "%s:%i (%s)", loc
->get_trimmed_filename (),
80 loc
->m_line
, loc
->m_function
);
84 fprintf (stderr
, "%-48s %10li:%4.1f%%%10li%10li:%4.1f%%%11li%11li\n", s
,
85 (long)m_allocated
, m_allocated
* 100.0 / total
.m_allocated
,
86 (long)m_peak
, (long)m_times
, m_times
* 100.0 / total
.m_times
,
87 (long)m_items
, (long)m_items_peak
);
95 fprintf (stderr
, "%s%55li%25li%17li\n", "Total", (long)m_allocated
,
96 (long)m_times
, (long)m_items
);
100 /* Dump header with NAME. */
102 dump_header (const char *name
)
104 fprintf (stderr
, "%-48s %11s%15s%10s%17s%11s\n", name
, "Leak", "Peak",
105 "Times", "Leak items", "Peak items");
109 /* Current number of items allocated. */
111 /* Peak value of number of allocated items. */
115 /* Vector memory description. */
116 static mem_alloc_description
<vec_usage
> vec_mem_desc
;
118 /* Account the overhead. */
121 vec_prefix::register_overhead (void *ptr
, size_t size
, size_t elements
124 vec_mem_desc
.register_descriptor (ptr
, VEC_ORIGIN
, false
125 FINAL_PASS_MEM_STAT
);
126 vec_usage
*usage
= vec_mem_desc
.register_instance_overhead (size
, ptr
);
127 usage
->m_items
+= elements
;
128 if (usage
->m_items_peak
< usage
->m_items
)
129 usage
->m_items_peak
= usage
->m_items
;
132 /* Notice that the memory allocated for the vector has been freed. */
135 vec_prefix::release_overhead (void *ptr
, size_t size
, bool in_dtor
138 if (!vec_mem_desc
.contains_descriptor_for_instance (ptr
))
139 vec_mem_desc
.register_descriptor (ptr
, VEC_ORIGIN
,
140 false FINAL_PASS_MEM_STAT
);
141 vec_mem_desc
.release_instance_overhead (ptr
, size
, in_dtor
);
145 /* Calculate the number of slots to reserve a vector, making sure that
146 it is of at least DESIRED size by growing ALLOC exponentially. */
149 vec_prefix::calculate_allocation_1 (unsigned alloc
, unsigned desired
)
151 /* We must have run out of room. */
152 gcc_assert (alloc
< desired
);
154 /* Exponential growth. */
158 /* Double when small. */
161 /* Grow slower when large. */
162 alloc
= (alloc
* 3 / 2);
164 /* If this is still too small, set it to the right size. */
170 /* Dump per-site memory statistics. */
173 dump_vec_loc_statistics (void)
175 vec_mem_desc
.dump (VEC_ORIGIN
);
179 /* Report qsort comparator CMP consistency check failure with P1, P2, P3 as
181 ATTRIBUTE_NORETURN ATTRIBUTE_COLD
183 qsort_chk_error (const void *p1
, const void *p2
, const void *p3
,
184 int (*cmp
) (const void *, const void *))
188 int r1
= cmp (p1
, p2
), r2
= cmp (p2
, p1
);
189 error ("qsort comparator not anti-commutative: %d, %d", r1
, r2
);
193 int r
= cmp (p1
, p3
);
194 error ("qsort comparator non-negative on sorted output: %d", r
);
198 int r1
= cmp (p1
, p2
), r2
= cmp (p2
, p3
), r3
= cmp (p1
, p3
);
199 error ("qsort comparator not transitive: %d, %d, %d", r1
, r2
, r3
);
201 internal_error ("qsort checking failed");
204 /* Wrapper around qsort with checking that CMP is consistent on given input.
206 Strictly speaking, passing invalid (non-transitive, non-anti-commutative)
207 comparators to libc qsort can result in undefined behavior. Therefore we
208 should ideally perform consistency checks prior to invoking qsort, but in
209 order to do that optimally we'd need to sort the array ourselves beforehand
210 with a sorting routine known to be "safe". Instead, we expect that most
211 implementations in practice will still produce some permutation of input
212 array even for invalid comparators, which enables us to perform checks on
215 qsort_chk (void *base
, size_t n
, size_t size
,
216 int (*cmp
)(const void *, const void *))
218 (qsort
) (base
, n
, size
, cmp
);
222 /* Limit overall time complexity to O(n log n). */
223 #define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n))
225 #define ELT(i) ((const char *) base + (i) * size)
226 #define CMP(i, j) cmp (ELT (i), ELT (j))
227 #define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp)
228 #define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp)
230 /* This outer loop iterates over maximum spans [i1, i2) such that
231 elements within each span compare equal to each other. */
232 for (i1
= 0; i1
< n
; i1
= i2
)
234 /* Position i2 one past last element that compares equal to i1'th. */
235 for (i2
= i1
+ 1; i2
< n
; i2
++)
238 else if (CMP (i2
, i1
))
239 return ERR2 (i1
, i2
);
240 size_t lim1
= LIM (i2
- i1
), lim2
= LIM (n
- i2
);
241 /* Verify that other pairs within current span compare equal. */
242 for (i
= i1
+ 1; i
+ 1 < i2
; i
++)
243 for (j
= i
+ 1; j
< i1
+ lim1
; j
++)
245 return ERR3 (i
, i1
, j
);
248 /* Verify that elements within this span compare less than
249 elements beyond the span. */
250 for (i
= i1
; i
< i2
; i
++)
251 for (j
= i2
; j
< i2
+ lim2
; j
++)
253 return ERR3 (i
, i1
, j
);
254 else if (CMP (j
, i
) <= 0)
263 #endif /* #if CHECKING_P */
265 #ifndef GENERATOR_FILE
272 /* Call V.safe_push for all ints from START up to, but not including LIMIT.
273 Helper function for selftests. */
276 safe_push_range (vec
<int>&v
, int start
, int limit
)
278 for (int i
= start
; i
< limit
; i
++)
282 /* Verify that vec::quick_push works correctly. */
288 ASSERT_EQ (0, v
.length ());
290 ASSERT_EQ (0, v
.length ());
291 ASSERT_TRUE (v
.space (3));
295 ASSERT_EQ (3, v
.length ());
301 /* Verify that vec::safe_push works correctly. */
307 ASSERT_EQ (0, v
.length ());
311 ASSERT_EQ (3, v
.length ());
317 /* Verify that vec::truncate works correctly. */
323 ASSERT_EQ (0, v
.length ());
324 safe_push_range (v
, 0, 10);
325 ASSERT_EQ (10, v
.length ());
328 ASSERT_EQ (5, v
.length ());
331 /* Verify that vec::safe_grow_cleared works correctly. */
334 test_safe_grow_cleared ()
337 ASSERT_EQ (0, v
.length ());
338 v
.safe_grow_cleared (50);
339 ASSERT_EQ (50, v
.length ());
341 ASSERT_EQ (0, v
[49]);
344 /* Verify that vec::pop works correctly. */
350 safe_push_range (v
, 5, 20);
351 ASSERT_EQ (15, v
.length ());
354 ASSERT_EQ (19, last
);
355 ASSERT_EQ (14, v
.length ());
358 /* Verify that vec::safe_insert works correctly. */
364 safe_push_range (v
, 0, 10);
365 v
.safe_insert (5, 42);
367 ASSERT_EQ (42, v
[5]);
369 ASSERT_EQ (11, v
.length ());
372 /* Verify that vec::ordered_remove works correctly. */
375 test_ordered_remove ()
378 safe_push_range (v
, 0, 10);
379 v
.ordered_remove (5);
382 ASSERT_EQ (9, v
.length ());
385 /* Verify that vec::unordered_remove works correctly. */
388 test_unordered_remove ()
391 safe_push_range (v
, 0, 10);
392 v
.unordered_remove (5);
393 ASSERT_EQ (9, v
.length ());
396 /* Verify that vec::block_remove works correctly. */
402 safe_push_range (v
, 0, 10);
403 v
.block_remove (5, 3);
408 ASSERT_EQ (7, v
.length ());
411 /* Comparator for use by test_qsort. */
414 reverse_cmp (const void *p_i
, const void *p_j
)
416 return *(const int *)p_j
- *(const int *)p_i
;
419 /* Verify that vec::qsort works correctly. */
425 safe_push_range (v
, 0, 10);
426 v
.qsort (reverse_cmp
);
431 ASSERT_EQ (10, v
.length ());
434 /* Run all of the selftests within this file. */
442 test_safe_grow_cleared ();
445 test_ordered_remove ();
446 test_unordered_remove ();
447 test_block_remove ();
451 } // namespace selftest
453 #endif /* #if CHECKING_P */
454 #endif /* #ifndef GENERATOR_FILE */