00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #ifdef USE_PCH
00063 #include "cg_pch.h"
00064 #endif // USE_PCH
00065 #pragma hdrstop
00066
00067 #ifdef _KEEP_RCS_ID
00068 static const char *source_file = __FILE__;
00069 static const char *rcs_id = "$Source: /scratch/mee/2.4-65/kpro64-pending/be/cg/SCCS/s.op_map.cxx $ $Revision: 1.6 $";
00070 #endif
00071
00072 #include "defs.h"
00073 #include "errors.h"
00074 #include "mempool.h"
00075 #include "cgir.h"
00076
00077 #ifdef DEBUG
00078 #define inline static
00079 #endif
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 static BB *idx_op_bb;
00097 static OP **idx_ops;
00098 static UINT16 idx_ops_length;
00099 static MEM_POOL idx_op_pool;
00100
00101
00102 static void init_idx_ops(void)
00103 {
00104 idx_op_bb = NULL;
00105 MEM_POOL_Initialize(&idx_op_pool, "OP_MAP_Idx_Op_pool", TRUE);
00106 MEM_POOL_Push(&idx_op_pool);
00107 }
00108
00109
00110 static void finish_idx_ops(void)
00111 {
00112 MEM_POOL_Pop(&idx_op_pool);
00113 MEM_POOL_Delete(&idx_op_pool);
00114 }
00115
00116
00117 static void create_idx_ops(BB *bb)
00118
00119
00120
00121
00122 {
00123 UINT16 next_idx = BB_next_op_map_idx(bb);
00124 OP *op;
00125
00126
00127 MEM_POOL_Pop(&idx_op_pool);
00128 MEM_POOL_Push(&idx_op_pool);
00129
00130
00131 idx_ops = TYPE_MEM_POOL_ALLOC_N(OP *, &idx_op_pool, next_idx);
00132 idx_ops_length = next_idx;
00133 idx_op_bb = bb;
00134
00135
00136 for (op = BB_first_op(bb); op; op = OP_next(op)) {
00137 Is_True(OP_map_idx(op) < next_idx,
00138 ("OP_map_idx out of range"));
00139 idx_ops[OP_map_idx(op)] = op;
00140 }
00141 }
00142
00143
00144 OP *OP_MAP_Idx_Op(BB *bb, UINT16 idx)
00145 {
00146
00147 if (bb != idx_op_bb) {
00148
00149
00150
00151 create_idx_ops(bb);
00152 }
00153
00154 if (idx >= idx_ops_length) {
00155 if (idx < BB_next_op_map_idx(bb)) {
00156
00157
00158
00159 create_idx_ops(bb);
00160 } else {
00161
00162 return NULL;
00163 }
00164 }
00165
00166 Is_True(idx_ops[idx] == NULL || OP_map_idx(idx_ops[idx]) == idx,
00167 ("OP_map_idx disagrees with OP_MAP_Idx_Op"));
00168 return idx_ops[idx];
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 typedef union value {
00183
00184
00185
00186
00187
00188
00189 mINT32 i32;
00190 void *ptr;
00191 mINT64 i64;
00192 } VALUE;
00193
00194
00195 typedef struct hash_entry {
00196 const OP *key;
00197
00198 struct hash_entry *next;
00199
00200 VALUE val;
00201
00202 } HASH_ENTRY;
00203
00204 #define MAX_BUCKETS_LOG2 32
00205
00206 typedef struct hash_table {
00207 UINT8 length_log2;
00208
00209 HASH_ENTRY **buckets;
00210
00211 mUINT32 gen;
00212 mUINT32 *bucket_gens;
00213
00214 struct hash_table *next_free;
00215 } HASH_TABLE;
00216
00217
00218 static HASH_TABLE *free_tables[MAX_BUCKETS_LOG2+1];
00219 #define next_free_table(tbl) ((tbl)->next_free)
00220
00221 static HASH_ENTRY *free_entries;
00222 #define next_free_entry(entry) ((entry)->next)
00223
00224
00225 static void init_hash_tables(void)
00226 {
00227 BZERO(free_tables, sizeof(free_tables));
00228 free_entries = NULL;
00229 }
00230
00231
00232 static HASH_TABLE *hash_table_create(UINT8 length_log2)
00233
00234
00235
00236
00237 {
00238 HASH_TABLE *tbl;
00239
00240 Is_True(length_log2 <= MAX_BUCKETS_LOG2,
00241 ("can't make hash table with 2^%d buckets", length_log2));
00242
00243
00244
00245
00246
00247 tbl = free_tables[length_log2];
00248 if (tbl) {
00249 free_tables[length_log2] = next_free_table(tbl);
00250 tbl->gen += 1;
00251 if (tbl->gen == 0) {
00252 DevWarn("(Performance) OP_MAP generation overflow - zeroing");
00253 BZERO(tbl->bucket_gens, sizeof(mUINT32) * (1 << length_log2));
00254 tbl->gen = 1;
00255 }
00256 } else {
00257 tbl = TYPE_MEM_POOL_ALLOC(HASH_TABLE, &MEM_phase_nz_pool);
00258 tbl->length_log2 = length_log2;
00259 tbl->buckets = TYPE_MEM_POOL_ALLOC_N(HASH_ENTRY *, &MEM_phase_nz_pool,
00260 1 << length_log2);
00261 tbl->gen = 1;
00262
00263
00264
00265
00266 tbl->bucket_gens = TYPE_MEM_POOL_ALLOC_N(mUINT32, &MEM_phase_pool,
00267 1 << length_log2);
00268 }
00269 return tbl;
00270 }
00271
00272
00273 static void hash_table_delete(HASH_TABLE *tbl)
00274
00275
00276
00277
00278 {
00279
00280 next_free_table(tbl) = free_tables[tbl->length_log2];
00281 free_tables[tbl->length_log2] = tbl;
00282 }
00283
00284
00285 static HASH_ENTRY *hash_entry_create(void)
00286
00287
00288
00289
00290
00291 {
00292 HASH_ENTRY *entry = free_entries;
00293 if (entry) {
00294 free_entries = next_free_entry(free_entries);
00295 } else {
00296 entry = TYPE_MEM_POOL_ALLOC(HASH_ENTRY, &MEM_phase_nz_pool);
00297 }
00298 return entry;
00299 }
00300
00301
00302 static void hash_entries_delete(HASH_ENTRY *entries)
00303
00304
00305
00306
00307 {
00308 HASH_ENTRY *last = entries;
00309 while (last->next) last = last->next;
00310 next_free_entry(last) = free_entries;
00311 free_entries = entries;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 #define hash(key, len_log2) (((INTPTR)key >> 3) & ((1 << len_log2) - 1))
00323
00324
00325 inline HASH_ENTRY *hash_table_entry(HASH_TABLE *tbl, const OP *key, BOOL create)
00326
00327
00328
00329
00330
00331 {
00332 UINT32 idx = hash(key, tbl->length_log2);
00333
00334 if (tbl->bucket_gens[idx] == tbl->gen) {
00335
00336
00337
00338 HASH_ENTRY *entry = tbl->buckets[idx];
00339 Is_True(entry, ("initial bucket entry is NULL"));
00340 while (entry && entry->key != key)
00341 entry = entry->next;
00342
00343 if (entry == NULL && create) {
00344
00345
00346
00347 entry = hash_entry_create();
00348 entry->next = tbl->buckets[idx];
00349 tbl->buckets[idx] = entry;
00350 entry->key = key;
00351 }
00352
00353 return entry;
00354 }
00355
00356 if (create) {
00357 if (tbl->bucket_gens[idx] > 0) {
00358
00359
00360
00361 HASH_ENTRY *rest = tbl->buckets[idx]->next;
00362 if (rest) hash_entries_delete(rest);
00363 } else {
00364
00365
00366
00367 tbl->buckets[idx] = hash_entry_create();
00368 }
00369 tbl->buckets[idx]->key = key;
00370 tbl->buckets[idx]->next = NULL;
00371 tbl->bucket_gens[idx] = tbl->gen;
00372 return tbl->buckets[idx];
00373 }
00374
00375 return NULL;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385 struct op_map {
00386 OP_MAP_KIND kind;
00387 HASH_TABLE *tbl;
00388 struct op_map *next_free;
00389 };
00390
00391 OP_MAP free_maps;
00392 #define next_free_map(map) ((map)->next_free)
00393
00394
00395 void OP_MAP_Init(void)
00396 {
00397 init_hash_tables();
00398 init_idx_ops();
00399 free_maps = NULL;
00400 }
00401
00402
00403 void OP_MAP_Finish(void)
00404 {
00405 finish_idx_ops();
00406 }
00407
00408
00409 OP_MAP _OP_MAP_Create(OP_MAP_KIND kind)
00410
00411
00412
00413
00414 {
00415 OP_MAP result;
00416
00417
00418 if (free_maps) {
00419 result = free_maps;
00420 free_maps = next_free_map(free_maps);
00421 Is_True(result->kind == OP_MAP_DELETED,
00422 ("map from free list not marked OP_MAP_DELETED"));
00423 } else {
00424
00425 result = TYPE_MEM_POOL_ALLOC(struct op_map, &MEM_phase_nz_pool);
00426 }
00427
00428 result->kind = kind;
00429
00430 result->tbl = hash_table_create(9);
00431
00432 return result;
00433 }
00434
00435
00436 void OP_MAP_Delete(OP_MAP map)
00437 {
00438
00439 hash_table_delete(map->tbl);
00440
00441
00442
00443 map->kind = OP_MAP_DELETED;
00444 next_free_map(map) = free_maps;
00445 free_maps = map;
00446 }
00447
00448 #ifdef TARG_IA64
00449 BOOL OP_MAP_Is_Delete(OP_MAP map)
00450 {
00451 return map->kind == OP_MAP_DELETED;
00452 }
00453 #endif
00454
00455 void OP_MAP_Set(OP_MAP map, OP *op, void *value)
00456 {
00457 HASH_ENTRY *entry = hash_table_entry(map->tbl, op, TRUE);
00458 Is_True(map->kind != OP_MAP_DELETED, ("accessing deleted OP_MAP"));
00459 Is_True(map->kind == OP_MAP_PTR, ("OP_MAP is of wrong kind"));
00460 entry->val.ptr = value;
00461 }
00462
00463
00464 void OP_MAP32_Set(OP_MAP map, OP *op, INT32 value)
00465 {
00466 HASH_ENTRY *entry = hash_table_entry(map->tbl, op, TRUE);
00467 Is_True(map->kind != OP_MAP_DELETED, ("accessing deleted OP_MAP"));
00468 Is_True(map->kind == OP_MAP_I32, ("OP_MAP is of wrong kind"));
00469 entry->val.i32 = value;
00470 }
00471
00472
00473 void OP_MAP64_Set(OP_MAP map, OP *op, INT64 value)
00474 {
00475 HASH_ENTRY *entry = hash_table_entry(map->tbl, op, TRUE);
00476 Is_True(map->kind != OP_MAP_DELETED, ("accessing deleted OP_MAP"));
00477 Is_True(map->kind == OP_MAP_I64, ("OP_MAP is of wrong kind"));
00478 entry->val.i64 = value;
00479 }
00480
00481
00482 void *OP_MAP_Get(OP_MAP map, const OP *op)
00483 {
00484 HASH_ENTRY *entry = hash_table_entry(map->tbl, op, FALSE);
00485 Is_True(map->kind != OP_MAP_DELETED, ("accessing deleted OP_MAP"));
00486 Is_True(map->kind == OP_MAP_PTR, ("OP_MAP is of wrong kind"));
00487 return entry ? entry->val.ptr : NULL;
00488 }
00489
00490
00491 INT32 OP_MAP32_Get(OP_MAP map, const OP *op)
00492 {
00493 HASH_ENTRY *entry = hash_table_entry(map->tbl, op, FALSE);
00494 Is_True(map->kind != OP_MAP_DELETED, ("accessing deleted OP_MAP"));
00495 Is_True(map->kind == OP_MAP_I32, ("OP_MAP is of wrong kind"));
00496 return entry ? entry->val.i32 : 0;
00497 }
00498
00499
00500 INT64 OP_MAP64_Get(OP_MAP map, const OP *op)
00501 {
00502 HASH_ENTRY *entry = hash_table_entry(map->tbl, op, FALSE);
00503 Is_True(map->kind != OP_MAP_DELETED, ("accessing deleted OP_MAP"));
00504 Is_True(map->kind == OP_MAP_I64, ("OP_MAP is of wrong kind"));
00505 return entry ? entry->val.i64 : 0;
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 BB_OP_MAP BB_OP_MAP_Create_Kind(BB *bb, MEM_POOL *pool, OP_MAP_KIND kind)
00519
00520
00521
00522
00523 {
00524 INT32 size;
00525 BB_OP_MAP new_map = TYPE_MEM_POOL_ALLOC(struct bb_op_map, pool);
00526 #ifdef TARG_IA64
00527 INT32 nelem = BB_next_op_map_idx(bb) + 20;
00528 #else
00529 INT32 nelem = BB_next_op_map_idx(bb);
00530 #endif
00531
00532 new_map->bb = bb;
00533 new_map->kind = kind;
00534 new_map->pool = pool;
00535 new_map->nelem = nelem;
00536
00537 switch (kind) {
00538 case OP_MAP_I32:
00539 size = nelem * sizeof(INT32);
00540 break;
00541 case OP_MAP_I64:
00542 size = nelem * sizeof(INT64);
00543 break;
00544 default:
00545 FmtAssert(FALSE, ("unexpected BB_OP_MAP kind"));
00546
00547 case OP_MAP_PTR:
00548 size = nelem * sizeof(void *);
00549 break;
00550 }
00551
00552 new_map->themap.ptr = (void **) MEM_POOL_Alloc(pool, size);
00553 if (!MEM_POOL_Zeroed(pool)) BZERO (new_map->themap.ptr, size);
00554
00555 return new_map;
00556 }
00557
00558
00559 void BB_OP_MAP_Extend_Map(BB_OP_MAP map, OP *op)
00560
00561
00562
00563
00564 {
00565 INT32 idx = OP_map_idx(op);
00566 enum { INCR_PERCENT = 10 };
00567
00568 FmtAssert(OP_bb(op) == map->bb, ("OP is not in BB_OP_MAP BB"));
00569
00570 if (idx >= map->nelem) {
00571 INT32 elem_size;
00572 INT32 new_nelem = (BB_next_op_map_idx(map->bb) * (100 + INCR_PERCENT)) / 100;
00573 INT32 old_nelem = map->nelem;
00574 new_nelem = MAX(old_nelem * 2, new_nelem);
00575 FmtAssert(new_nelem > idx, ("OP map index is out of range"));
00576
00577 switch (map->kind) {
00578 case OP_MAP_I32:
00579 elem_size = sizeof(INT32);
00580 break;
00581 case OP_MAP_I64:
00582 elem_size = sizeof(INT64);
00583 break;
00584 case OP_MAP_PTR:
00585 elem_size = sizeof(void *);
00586 break;
00587 }
00588
00589 map->themap.ptr = (void **) MEM_POOL_Realloc(map->pool,
00590 map->themap.ptr,
00591 old_nelem * elem_size,
00592 new_nelem * elem_size);
00593 if (!MEM_POOL_Zeroed(map->pool)) {
00594 BZERO((char *)map->themap.ptr + (old_nelem * elem_size),
00595 elem_size * (new_nelem - old_nelem));
00596 }
00597
00598 map->nelem = new_nelem;
00599 }
00600 }