150397Sobrien/* Virtual array support.
2169689Skan   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
3132718Skan   Free Software Foundation, Inc.
450397Sobrien   Contributed by Cygnus Solutions.
550397Sobrien
690075Sobrien   This file is part of GCC.
750397Sobrien
890075Sobrien   GCC is free software; you can redistribute it and/or modify it
950397Sobrien   under the terms of the GNU General Public License as published by
1050397Sobrien   the Free Software Foundation; either version 2, or (at your option)
1150397Sobrien   any later version.
1250397Sobrien
1390075Sobrien   GCC is distributed in the hope that it will be useful, but WITHOUT
1490075Sobrien   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1590075Sobrien   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1690075Sobrien   License for more details.
1750397Sobrien
1850397Sobrien   You should have received a copy of the GNU General Public License
1990075Sobrien   along with GCC; see the file COPYING.  If not, write to the Free
20169689Skan   the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
21169689Skan   MA 02110-1301, USA.  */
2250397Sobrien
2350397Sobrien#include "config.h"
2450397Sobrien#include "system.h"
25132718Skan#include "coretypes.h"
26132718Skan#include "tm.h"
27169689Skan#include "toplev.h"
2850397Sobrien#include "varray.h"
29117395Skan#include "ggc.h"
30132718Skan#include "hashtab.h"
3150397Sobrien
3250397Sobrien#define VARRAY_HDR_SIZE (sizeof (struct varray_head_tag) - sizeof (varray_data))
3350397Sobrien
34132718Skan#ifdef GATHER_STATISTICS
35132718Skan
36169689Skan/* Store information about each particular varray.  */
37132718Skanstruct varray_descriptor
38132718Skan{
39132718Skan  const char *name;
40132718Skan  int allocated;
41132718Skan  int created;
42132718Skan  int resized;
43132718Skan  int copied;
44117395Skan};
45117395Skan
46132718Skan/* Hashtable mapping varray names to descriptors.  */
47132718Skanstatic htab_t varray_hash;
48132718Skan
49132718Skan/* Hashtable helpers.  */
50132718Skanstatic hashval_t
51132718Skanhash_descriptor (const void *p)
52132718Skan{
53132718Skan  const struct varray_descriptor *d = p;
54132718Skan  return htab_hash_pointer (d->name);
55132718Skan}
56132718Skanstatic int
57132718Skaneq_descriptor (const void *p1, const void *p2)
58132718Skan{
59132718Skan  const struct varray_descriptor *d = p1;
60132718Skan  return d->name == p2;
61132718Skan}
62132718Skan
63132718Skan/* For given name, return descriptor, create new if needed.  */
64132718Skanstatic struct varray_descriptor *
65132718Skanvarray_descriptor (const char *name)
66132718Skan{
67132718Skan  struct varray_descriptor **slot;
68132718Skan
69132718Skan  if (!varray_hash)
70132718Skan    varray_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
71132718Skan
72132718Skan  slot = (struct varray_descriptor **)
73132718Skan    htab_find_slot_with_hash (varray_hash, name,
74132718Skan		    	      htab_hash_pointer (name),
75132718Skan			      1);
76132718Skan  if (*slot)
77132718Skan    return *slot;
78132718Skan  *slot = xcalloc (sizeof (**slot), 1);
79132718Skan  (*slot)->name = name;
80132718Skan  return *slot;
81132718Skan}
82132718Skan#endif
83132718Skan
84132718Skan/* Do not add any more non-GC items here.  Please either remove or GC
85132718Skan   those items that are not GCed.  */
86132718Skan
87132718Skanstatic const struct {
88132718Skan  unsigned char size;
89132718Skan  bool uses_ggc;
90132718Skan} element[NUM_VARRAY_DATA] = {
91132718Skan  { sizeof (char), 1 },
92132718Skan  { sizeof (unsigned char), 1 },
93132718Skan  { sizeof (short), 1 },
94132718Skan  { sizeof (unsigned short), 1 },
95132718Skan  { sizeof (int), 1 },
96132718Skan  { sizeof (unsigned int), 1 },
97132718Skan  { sizeof (long), 1 },
98132718Skan  { sizeof (unsigned long), 1 },
99132718Skan  { sizeof (HOST_WIDE_INT), 1 },
100132718Skan  { sizeof (unsigned HOST_WIDE_INT), 1 },
101132718Skan  { sizeof (void *), 1 },
102169689Skan  { sizeof (void *), 0 },
103132718Skan  { sizeof (char *), 1 },
104132718Skan  { sizeof (struct rtx_def *), 1 },
105132718Skan  { sizeof (struct rtvec_def *), 1 },
106132718Skan  { sizeof (union tree_node *), 1 },
107132718Skan  { sizeof (struct bitmap_head_def *), 1 },
108132718Skan  { sizeof (struct reg_info_def *), 0 },
109169689Skan  { sizeof (struct basic_block_def *), 1 },
110132718Skan  { sizeof (struct elt_list *), 1 },
111169689Skan  { sizeof (struct edge_def *), 1 },
112169689Skan  { sizeof (tree *), 1 },
113117395Skan};
114117395Skan
11550397Sobrien/* Allocate a virtual array with NUM_ELEMENT elements, each of which is
11650397Sobrien   ELEMENT_SIZE bytes long, named NAME.  Array elements are zeroed.  */
11750397Sobrienvarray_type
118132718Skanvarray_init (size_t num_elements, enum varray_data_enum element_kind,
119132718Skan	     const char *name)
12050397Sobrien{
121132718Skan  size_t data_size = num_elements * element[element_kind].size;
122117395Skan  varray_type ptr;
123132718Skan#ifdef GATHER_STATISTICS
124132718Skan  struct varray_descriptor *desc = varray_descriptor (name);
125132718Skan
126132718Skan  desc->created++;
127132718Skan  desc->allocated += data_size + VARRAY_HDR_SIZE;
128132718Skan#endif
129132718Skan  if (element[element_kind].uses_ggc)
130132718Skan    ptr = ggc_alloc_cleared (VARRAY_HDR_SIZE + data_size);
131117395Skan  else
132132718Skan    ptr = xcalloc (VARRAY_HDR_SIZE + data_size, 1);
13350397Sobrien
13450397Sobrien  ptr->num_elements = num_elements;
13590075Sobrien  ptr->elements_used = 0;
136117395Skan  ptr->type = element_kind;
13790075Sobrien  ptr->name = name;
13850397Sobrien  return ptr;
13950397Sobrien}
14050397Sobrien
14150397Sobrien/* Grow/shrink the virtual array VA to N elements.  Zero any new elements
14250397Sobrien   allocated.  */
14350397Sobrienvarray_type
144132718Skanvarray_grow (varray_type va, size_t n)
14550397Sobrien{
14650397Sobrien  size_t old_elements = va->num_elements;
14750397Sobrien  if (n != old_elements)
14850397Sobrien    {
149132718Skan      size_t elem_size = element[va->type].size;
150117395Skan      size_t old_data_size = old_elements * elem_size;
151117395Skan      size_t data_size = n * elem_size;
152132718Skan#ifdef GATHER_STATISTICS
153132718Skan      struct varray_descriptor *desc = varray_descriptor (va->name);
154132718Skan      varray_type oldva = va;
15550397Sobrien
156132718Skan      if (data_size > old_data_size)
157132718Skan        desc->allocated += data_size - old_data_size;
158132718Skan      desc->resized ++;
159132718Skan#endif
160132718Skan
161132718Skan
162132718Skan      if (element[va->type].uses_ggc)
163132718Skan	va = ggc_realloc (va, VARRAY_HDR_SIZE + data_size);
164117395Skan      else
165132718Skan	va = xrealloc (va, VARRAY_HDR_SIZE + data_size);
16650397Sobrien      va->num_elements = n;
16750397Sobrien      if (n > old_elements)
168169689Skan	memset (&va->data.vdt_c[old_data_size], 0, data_size - old_data_size);
169132718Skan#ifdef GATHER_STATISTICS
170132718Skan      if (oldva != va)
171132718Skan        desc->copied++;
172132718Skan#endif
17350397Sobrien    }
17450397Sobrien
17550397Sobrien  return va;
17650397Sobrien}
17790075Sobrien
178117395Skan/* Reset a varray to its original state.  */
179117395Skanvoid
180132718Skanvarray_clear (varray_type va)
181117395Skan{
182132718Skan  size_t data_size = element[va->type].size * va->num_elements;
183117395Skan
184169689Skan  memset (va->data.vdt_c, 0, data_size);
185117395Skan  va->elements_used = 0;
186117395Skan}
187117395Skan
18890075Sobrien/* Check the bounds of a varray access.  */
18990075Sobrien
19090075Sobrien#if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
19190075Sobrien
19290075Sobrienvoid
193132718Skanvarray_check_failed (varray_type va, size_t n, const char *file, int line,
194132718Skan		     const char *function)
19590075Sobrien{
196132718Skan  internal_error ("virtual array %s[%lu]: element %lu out of bounds "
197132718Skan		  "in %s, at %s:%d",
19890075Sobrien		  va->name, (unsigned long) va->num_elements, (unsigned long) n,
19990075Sobrien		  function, trim_filename (file), line);
20090075Sobrien}
20190075Sobrien
202132718Skanvoid
203132718Skanvarray_underflow (varray_type va, const char *file, int line,
204132718Skan		  const char *function)
205132718Skan{
206132718Skan  internal_error ("underflowed virtual array %s in %s, at %s:%d",
207132718Skan		  va->name, function, trim_filename (file), line);
208132718Skan}
209132718Skan
21090075Sobrien#endif
211132718Skan
212169689Skan
213132718Skan/* Output per-varray statistics.  */
214132718Skan#ifdef GATHER_STATISTICS
215169689Skan
216169689Skan/* Used to accumulate statistics about varray sizes.  */
217132718Skanstruct output_info
218132718Skan{
219132718Skan  int count;
220132718Skan  int size;
221132718Skan};
222169689Skan
223169689Skan/* Called via htab_traverse.  Output varray descriptor pointed out by SLOT
224169689Skan   and update statistics.  */
225132718Skanstatic int
226132718Skanprint_statistics (void **slot, void *b)
227132718Skan{
228132718Skan  struct varray_descriptor *d = (struct varray_descriptor *) *slot;
229132718Skan  struct output_info *i = (struct output_info *) b;
230132718Skan
231132718Skan  if (d->allocated)
232132718Skan    {
233132718Skan      fprintf (stderr, "%-21s %6d %10d %7d %7d\n", d->name,
234132718Skan	       d->created, d->allocated, d->resized, d->copied);
235132718Skan      i->size += d->allocated;
236132718Skan      i->count += d->created;
237132718Skan    }
238132718Skan  return 1;
239132718Skan}
240132718Skan#endif
241169689Skan
242169689Skan/* Output per-varray memory usage statistics.  */
243169689Skanvoid
244169689Skandump_varray_statistics (void)
245132718Skan{
246132718Skan#ifdef GATHER_STATISTICS
247132718Skan  struct output_info info;
248132718Skan
249132718Skan  fprintf (stderr, "\nVARRAY Kind            Count      Bytes  Resized copied\n");
250132718Skan  fprintf (stderr, "-------------------------------------------------------\n");
251132718Skan  info.count = 0;
252132718Skan  info.size = 0;
253132718Skan  htab_traverse (varray_hash, print_statistics, &info);
254132718Skan  fprintf (stderr, "-------------------------------------------------------\n");
255132718Skan  fprintf (stderr, "%-20s %7d %10d\n",
256132718Skan	   "Total", info.count, info.size);
257132718Skan  fprintf (stderr, "-------------------------------------------------------\n");
258132718Skan#endif
259132718Skan}
260