1 /* Vector API for GNU compiler.
2 Copyright (C) 2004-2020 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 class vec_usage
: public mem_usage
55 /* Default constructor. */
56 vec_usage (): m_items (0), m_items_peak (0), m_element_size (0) {}
59 vec_usage (size_t allocated
, size_t times
, size_t peak
,
60 size_t items
, size_t items_peak
, size_t element_size
)
61 : mem_usage (allocated
, times
, peak
),
62 m_items (items
), m_items_peak (items_peak
),
63 m_element_size (element_size
) {}
65 /* Sum the usage with SECOND usage. */
67 operator+ (const vec_usage
&second
)
69 return vec_usage (m_allocated
+ second
.m_allocated
,
70 m_times
+ second
.m_times
,
71 m_peak
+ second
.m_peak
,
72 m_items
+ second
.m_items
,
73 m_items_peak
+ second
.m_items_peak
, 0);
76 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
78 dump (mem_location
*loc
, mem_usage
&total
) const
81 sprintf (s
, "%s:%i (%s)", loc
->get_trimmed_filename (),
82 loc
->m_line
, loc
->m_function
);
87 "%-48s %10" PRIu64
PRsa (10) ":%4.1f%%" PRsa (9) "%10" PRIu64
88 ":%4.1f%%" PRsa (10) PRsa (10) "\n",
90 (uint64_t)m_element_size
,
91 SIZE_AMOUNT (m_allocated
),
92 m_allocated
* 100.0 / total
.m_allocated
,
93 SIZE_AMOUNT (m_peak
), (uint64_t)m_times
,
94 m_times
* 100.0 / total
.m_times
,
95 SIZE_AMOUNT (m_items
), SIZE_AMOUNT (m_items_peak
));
102 fprintf (stderr
, "%s" PRsa (64) PRsa (25) PRsa (16) "\n",
103 "Total", SIZE_AMOUNT (m_allocated
),
104 SIZE_AMOUNT (m_times
), SIZE_AMOUNT (m_items
));
107 /* Dump header with NAME. */
109 dump_header (const char *name
)
111 fprintf (stderr
, "%-48s %10s%11s%16s%10s%17s%11s\n", name
, "sizeof(T)",
112 "Leak", "Peak", "Times", "Leak items", "Peak items");
115 /* Current number of items allocated. */
117 /* Peak value of number of allocated items. */
119 /* Size of element of the vector. */
120 size_t m_element_size
;
123 /* Vector memory description. */
124 static mem_alloc_description
<vec_usage
> vec_mem_desc
;
126 /* Account the overhead. */
129 vec_prefix::register_overhead (void *ptr
, size_t elements
,
130 size_t element_size MEM_STAT_DECL
)
132 vec_mem_desc
.register_descriptor (ptr
, VEC_ORIGIN
, false
133 FINAL_PASS_MEM_STAT
);
135 = vec_mem_desc
.register_instance_overhead (elements
* element_size
, ptr
);
136 usage
->m_element_size
= element_size
;
137 usage
->m_items
+= elements
;
138 if (usage
->m_items_peak
< usage
->m_items
)
139 usage
->m_items_peak
= usage
->m_items
;
142 /* Notice that the memory allocated for the vector has been freed. */
145 vec_prefix::release_overhead (void *ptr
, size_t size
, size_t elements
,
146 bool in_dtor MEM_STAT_DECL
)
148 if (!vec_mem_desc
.contains_descriptor_for_instance (ptr
))
149 vec_mem_desc
.register_descriptor (ptr
, VEC_ORIGIN
,
150 false FINAL_PASS_MEM_STAT
);
151 vec_usage
*usage
= vec_mem_desc
.release_instance_overhead (ptr
, size
,
153 usage
->m_items
-= elements
;
156 /* Calculate the number of slots to reserve a vector, making sure that
157 it is of at least DESIRED size by growing ALLOC exponentially. */
160 vec_prefix::calculate_allocation_1 (unsigned alloc
, unsigned desired
)
162 /* We must have run out of room. */
163 gcc_assert (alloc
< desired
);
165 /* Exponential growth. */
169 /* Double when small. */
172 /* Grow slower when large. */
173 alloc
= (alloc
* 3 / 2);
175 /* If this is still too small, set it to the right size. */
181 /* Dump per-site memory statistics. */
184 dump_vec_loc_statistics (void)
186 vec_mem_desc
.dump (VEC_ORIGIN
);
190 /* Report qsort comparator CMP consistency check failure with P1, P2, P3 as
192 ATTRIBUTE_NORETURN ATTRIBUTE_COLD
194 qsort_chk_error (const void *p1
, const void *p2
, const void *p3
,
195 sort_r_cmp_fn
*cmp
, void *data
)
199 int r1
= cmp (p1
, p2
, data
), r2
= cmp (p2
, p1
, data
);
200 error ("qsort comparator not anti-symmetric: %d, %d", r1
, r2
);
204 int r
= cmp (p1
, p3
, data
);
205 error ("qsort comparator non-negative on sorted output: %d", r
);
209 int r1
= cmp (p1
, p2
, data
);
210 int r2
= cmp (p2
, p3
, data
);
211 int r3
= cmp (p1
, p3
, data
);
212 error ("qsort comparator not transitive: %d, %d, %d", r1
, r2
, r3
);
214 internal_error ("qsort checking failed");
217 /* Verify anti-symmetry and transitivity for comparator CMP on sorted array
218 of N SIZE-sized elements pointed to by BASE. */
220 qsort_chk (void *base
, size_t n
, size_t size
, sort_r_cmp_fn
*cmp
, void *data
)
225 /* Limit overall time complexity to O(n log n). */
226 #define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n))
228 #define ELT(i) ((const char *) base + (i) * size)
229 #define CMP(i, j) cmp (ELT (i), ELT (j), data)
230 #define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp, data)
231 #define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp, data)
233 /* This outer loop iterates over maximum spans [i1, i2) such that
234 elements within each span compare equal to each other. */
235 for (i1
= 0; i1
< n
; i1
= i2
)
237 /* Position i2 one past last element that compares equal to i1'th. */
238 for (i2
= i1
+ 1; i2
< n
; i2
++)
241 else if (CMP (i2
, i1
))
242 return ERR2 (i1
, i2
);
243 size_t lim1
= LIM (i2
- i1
), lim2
= LIM (n
- i2
);
244 /* Verify that other pairs within current span compare equal. */
245 for (i
= i1
+ 1; i
+ 1 < i2
; i
++)
246 for (j
= i
+ 1; j
< i1
+ lim1
; j
++)
248 return ERR3 (i
, i1
, j
);
251 /* Verify that elements within this span compare less than
252 elements beyond the span. */
253 for (i
= i1
; i
< i2
; i
++)
254 for (j
= i2
; j
< i2
+ lim2
; j
++)
256 return ERR3 (i
, i1
, j
);
257 else if (CMP (j
, i
) <= 0)
266 #endif /* #if CHECKING_P */
268 #ifndef GENERATOR_FILE
275 /* Call V.safe_push for all ints from START up to, but not including LIMIT.
276 Helper function for selftests. */
279 safe_push_range (vec
<int>&v
, int start
, int limit
)
281 for (int i
= start
; i
< limit
; i
++)
285 /* Verify that vec::quick_push works correctly. */
291 ASSERT_EQ (0, v
.length ());
293 ASSERT_EQ (0, v
.length ());
294 ASSERT_TRUE (v
.space (3));
298 ASSERT_EQ (3, v
.length ());
304 /* Verify that vec::safe_push works correctly. */
310 ASSERT_EQ (0, v
.length ());
314 ASSERT_EQ (3, v
.length ());
320 /* Verify that vec::truncate works correctly. */
326 ASSERT_EQ (0, v
.length ());
327 safe_push_range (v
, 0, 10);
328 ASSERT_EQ (10, v
.length ());
331 ASSERT_EQ (5, v
.length ());
334 /* Verify that vec::safe_grow_cleared works correctly. */
337 test_safe_grow_cleared ()
340 ASSERT_EQ (0, v
.length ());
341 v
.safe_grow_cleared (50);
342 ASSERT_EQ (50, v
.length ());
344 ASSERT_EQ (0, v
[49]);
347 /* Verify that vec::pop works correctly. */
353 safe_push_range (v
, 5, 20);
354 ASSERT_EQ (15, v
.length ());
357 ASSERT_EQ (19, last
);
358 ASSERT_EQ (14, v
.length ());
361 /* Verify that vec::safe_insert works correctly. */
367 safe_push_range (v
, 0, 10);
368 v
.safe_insert (5, 42);
370 ASSERT_EQ (42, v
[5]);
372 ASSERT_EQ (11, v
.length ());
375 /* Verify that vec::ordered_remove works correctly. */
378 test_ordered_remove ()
381 safe_push_range (v
, 0, 10);
382 v
.ordered_remove (5);
385 ASSERT_EQ (9, v
.length ());
388 /* Verify that vec::ordered_remove_if works correctly. */
391 test_ordered_remove_if (void)
394 safe_push_range (v
, 0, 10);
397 VEC_ORDERED_REMOVE_IF (v
, ix
, ix2
, elem_ptr
,
398 *elem_ptr
== 5 || *elem_ptr
== 7);
402 ASSERT_EQ (8, v
.length ());
405 safe_push_range (v
, 0, 10);
406 VEC_ORDERED_REMOVE_IF_FROM_TO (v
, ix
, ix2
, elem_ptr
, 0, 6,
407 *elem_ptr
== 5 || *elem_ptr
== 7);
411 ASSERT_EQ (9, v
.length ());
414 safe_push_range (v
, 0, 10);
415 VEC_ORDERED_REMOVE_IF_FROM_TO (v
, ix
, ix2
, elem_ptr
, 0, 5,
416 *elem_ptr
== 5 || *elem_ptr
== 7);
417 VEC_ORDERED_REMOVE_IF_FROM_TO (v
, ix
, ix2
, elem_ptr
, 8, 10,
418 *elem_ptr
== 5 || *elem_ptr
== 7);
422 ASSERT_EQ (10, v
.length ());
425 safe_push_range (v
, 0, 10);
426 VEC_ORDERED_REMOVE_IF (v
, ix
, ix2
, elem_ptr
, *elem_ptr
== 5);
430 ASSERT_EQ (9, v
.length ());
433 /* Verify that vec::unordered_remove works correctly. */
436 test_unordered_remove ()
439 safe_push_range (v
, 0, 10);
440 v
.unordered_remove (5);
441 ASSERT_EQ (9, v
.length ());
444 /* Verify that vec::block_remove works correctly. */
450 safe_push_range (v
, 0, 10);
451 v
.block_remove (5, 3);
456 ASSERT_EQ (7, v
.length ());
459 /* Comparator for use by test_qsort. */
462 reverse_cmp (const void *p_i
, const void *p_j
)
464 return *(const int *)p_j
- *(const int *)p_i
;
467 /* Verify that vec::qsort works correctly. */
473 safe_push_range (v
, 0, 10);
474 v
.qsort (reverse_cmp
);
479 ASSERT_EQ (10, v
.length ());
482 /* Verify that vec::reverse works correctly. */
487 /* Reversing an empty vec ought to be a no-op. */
490 ASSERT_EQ (0, v
.length ());
492 ASSERT_EQ (0, v
.length ());
495 /* Verify reversing a vec with even length. */
498 safe_push_range (v
, 0, 4);
504 ASSERT_EQ (4, v
.length ());
507 /* Verify reversing a vec with odd length. */
510 safe_push_range (v
, 0, 3);
515 ASSERT_EQ (3, v
.length ());
519 /* A test class that increments a counter every time its dtor is called. */
524 count_dtor (int *counter
) : m_counter (counter
) {}
525 ~count_dtor () { (*m_counter
)++; }
531 /* Verify that auto_delete_vec deletes the elements within it. */
534 test_auto_delete_vec ()
538 auto_delete_vec
<count_dtor
> v
;
539 v
.safe_push (new count_dtor (&dtor_count
));
540 v
.safe_push (new count_dtor (&dtor_count
));
542 ASSERT_EQ (dtor_count
, 2);
545 /* Run all of the selftests within this file. */
553 test_safe_grow_cleared ();
556 test_ordered_remove ();
557 test_ordered_remove_if ();
558 test_unordered_remove ();
559 test_block_remove ();
562 test_auto_delete_vec ();
565 } // namespace selftest
567 #endif /* #if CHECKING_P */
568 #endif /* #ifndef GENERATOR_FILE */