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