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 /* Verify anti-symmetry and transitivity for comparator CMP on sorted array
205 of N SIZE-sized elements pointed to by BASE. */
207 qsort_chk (void *base
, size_t n
, size_t size
,
208 int (*cmp
)(const void *, const void *))
213 /* Limit overall time complexity to O(n log n). */
214 #define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n))
216 #define ELT(i) ((const char *) base + (i) * size)
217 #define CMP(i, j) cmp (ELT (i), ELT (j))
218 #define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp)
219 #define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp)
221 /* This outer loop iterates over maximum spans [i1, i2) such that
222 elements within each span compare equal to each other. */
223 for (i1
= 0; i1
< n
; i1
= i2
)
225 /* Position i2 one past last element that compares equal to i1'th. */
226 for (i2
= i1
+ 1; i2
< n
; i2
++)
229 else if (CMP (i2
, i1
))
230 return ERR2 (i1
, i2
);
231 size_t lim1
= LIM (i2
- i1
), lim2
= LIM (n
- i2
);
232 /* Verify that other pairs within current span compare equal. */
233 for (i
= i1
+ 1; i
+ 1 < i2
; i
++)
234 for (j
= i
+ 1; j
< i1
+ lim1
; j
++)
236 return ERR3 (i
, i1
, j
);
239 /* Verify that elements within this span compare less than
240 elements beyond the span. */
241 for (i
= i1
; i
< i2
; i
++)
242 for (j
= i2
; j
< i2
+ lim2
; j
++)
244 return ERR3 (i
, i1
, j
);
245 else if (CMP (j
, i
) <= 0)
254 #endif /* #if CHECKING_P */
256 #ifndef GENERATOR_FILE
263 /* Call V.safe_push for all ints from START up to, but not including LIMIT.
264 Helper function for selftests. */
267 safe_push_range (vec
<int>&v
, int start
, int limit
)
269 for (int i
= start
; i
< limit
; i
++)
273 /* Verify that vec::quick_push works correctly. */
279 ASSERT_EQ (0, v
.length ());
281 ASSERT_EQ (0, v
.length ());
282 ASSERT_TRUE (v
.space (3));
286 ASSERT_EQ (3, v
.length ());
292 /* Verify that vec::safe_push works correctly. */
298 ASSERT_EQ (0, v
.length ());
302 ASSERT_EQ (3, v
.length ());
308 /* Verify that vec::truncate works correctly. */
314 ASSERT_EQ (0, v
.length ());
315 safe_push_range (v
, 0, 10);
316 ASSERT_EQ (10, v
.length ());
319 ASSERT_EQ (5, v
.length ());
322 /* Verify that vec::safe_grow_cleared works correctly. */
325 test_safe_grow_cleared ()
328 ASSERT_EQ (0, v
.length ());
329 v
.safe_grow_cleared (50);
330 ASSERT_EQ (50, v
.length ());
332 ASSERT_EQ (0, v
[49]);
335 /* Verify that vec::pop works correctly. */
341 safe_push_range (v
, 5, 20);
342 ASSERT_EQ (15, v
.length ());
345 ASSERT_EQ (19, last
);
346 ASSERT_EQ (14, v
.length ());
349 /* Verify that vec::safe_insert works correctly. */
355 safe_push_range (v
, 0, 10);
356 v
.safe_insert (5, 42);
358 ASSERT_EQ (42, v
[5]);
360 ASSERT_EQ (11, v
.length ());
363 /* Verify that vec::ordered_remove works correctly. */
366 test_ordered_remove ()
369 safe_push_range (v
, 0, 10);
370 v
.ordered_remove (5);
373 ASSERT_EQ (9, v
.length ());
376 /* Verify that vec::ordered_remove_if works correctly. */
379 test_ordered_remove_if (void)
382 safe_push_range (v
, 0, 10);
385 VEC_ORDERED_REMOVE_IF (v
, ix
, ix2
, elem_ptr
,
386 *elem_ptr
== 5 || *elem_ptr
== 7);
390 ASSERT_EQ (8, v
.length ());
393 safe_push_range (v
, 0, 10);
394 VEC_ORDERED_REMOVE_IF_FROM_TO (v
, ix
, ix2
, elem_ptr
, 0, 6,
395 *elem_ptr
== 5 || *elem_ptr
== 7);
399 ASSERT_EQ (9, v
.length ());
402 safe_push_range (v
, 0, 10);
403 VEC_ORDERED_REMOVE_IF_FROM_TO (v
, ix
, ix2
, elem_ptr
, 0, 5,
404 *elem_ptr
== 5 || *elem_ptr
== 7);
405 VEC_ORDERED_REMOVE_IF_FROM_TO (v
, ix
, ix2
, elem_ptr
, 8, 10,
406 *elem_ptr
== 5 || *elem_ptr
== 7);
410 ASSERT_EQ (10, v
.length ());
413 safe_push_range (v
, 0, 10);
414 VEC_ORDERED_REMOVE_IF (v
, ix
, ix2
, elem_ptr
, *elem_ptr
== 5);
418 ASSERT_EQ (9, v
.length ());
421 /* Verify that vec::unordered_remove works correctly. */
424 test_unordered_remove ()
427 safe_push_range (v
, 0, 10);
428 v
.unordered_remove (5);
429 ASSERT_EQ (9, v
.length ());
432 /* Verify that vec::block_remove works correctly. */
438 safe_push_range (v
, 0, 10);
439 v
.block_remove (5, 3);
444 ASSERT_EQ (7, v
.length ());
447 /* Comparator for use by test_qsort. */
450 reverse_cmp (const void *p_i
, const void *p_j
)
452 return *(const int *)p_j
- *(const int *)p_i
;
455 /* Verify that vec::qsort works correctly. */
461 safe_push_range (v
, 0, 10);
462 v
.qsort (reverse_cmp
);
467 ASSERT_EQ (10, v
.length ());
470 /* Verify that vec::reverse works correctly. */
475 /* Reversing an empty vec ought to be a no-op. */
478 ASSERT_EQ (0, v
.length ());
480 ASSERT_EQ (0, v
.length ());
483 /* Verify reversing a vec with even length. */
486 safe_push_range (v
, 0, 4);
492 ASSERT_EQ (4, v
.length ());
495 /* Verify reversing a vec with odd length. */
498 safe_push_range (v
, 0, 3);
503 ASSERT_EQ (3, v
.length ());
507 /* Run all of the selftests within this file. */
515 test_safe_grow_cleared ();
518 test_ordered_remove ();
519 test_ordered_remove_if ();
520 test_unordered_remove ();
521 test_block_remove ();
526 } // namespace selftest
528 #endif /* #if CHECKING_P */
529 #endif /* #ifndef GENERATOR_FILE */