blob: 73190244bfd3269eaa42bc6082d5d08653691a58 [file] [log] [blame]
Chris Lattner432312d2003-07-21 19:23:31 +00001/*===-- tracelib.c - Runtime routines for tracing ---------------*- C++ -*-===*\
2//
3// Runtime routines for supporting tracing of execution for code generated by
4// LLVM.
5//
6//===----------------------------------------------------------------------===*/
Vikram S. Adve2df1f742002-05-19 15:49:58 +00007
8#include "tracelib.h"
9#include <assert.h>
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
Joel Stanleyb1b3fb32003-06-24 02:46:47 +000013#ifndef sun
Chris Lattner3c4f63a2003-05-27 21:43:14 +000014#include <stdint.h>
Joel Stanleyb1b3fb32003-06-24 02:46:47 +000015#endif
Vikram S. Adve2df1f742002-05-19 15:49:58 +000016
17/*===---------------------------------------------------------------------=====
18 * HASH FUNCTIONS
19 *===---------------------------------------------------------------------===*/
20
21/* use #defines until we have inlining */
Vikram S. Advee04a2e02003-07-11 22:02:28 +000022typedef uint32_t Index; /* type of index/size for hash table */
23typedef uint32_t Generic; /* type of values stored in table */
Vikram S. Adve2df1f742002-05-19 15:49:58 +000024
25/* Index IntegerHashFunc(const Generic value, const Index size) */
26#define IntegerHashFunc(value, size) \
Vikram S. Advee04a2e02003-07-11 22:02:28 +000027 ( ((((Index) value) << 3) ^ (((Index) value) >> 3)) % size )
Vikram S. Adve2df1f742002-05-19 15:49:58 +000028
29/* Index IntegerRehashFunc(const Generic oldHashValue, const Index size) */
30#define IntegerRehashFunc(oldHashValue, size) \
Vikram S. Advee04a2e02003-07-11 22:02:28 +000031 ((Index) ((oldHashValue+16) % size)) /* 16 is relatively prime to a Mersenne prime! */
Vikram S. Adve2df1f742002-05-19 15:49:58 +000032
33/* Index PointerHashFunc(const void* value, const Index size) */
34#define PointerHashFunc(value, size) \
Vikram S. Advee04a2e02003-07-11 22:02:28 +000035 IntegerHashFunc((Index) value, size)
Vikram S. Adve2df1f742002-05-19 15:49:58 +000036
37/* Index PointerRehashFunc(const void* value, const Index size) */
38#define PointerRehashFunc(value, size) \
Vikram S. Advee04a2e02003-07-11 22:02:28 +000039 IntegerRehashFunc((Index) value, size)
Vikram S. Adve2df1f742002-05-19 15:49:58 +000040
41
42/*===---------------------------------------------------------------------=====
43 * POINTER-TO-GENERIC HASH TABLE.
44 * These should be moved to a separate location: HashTable.[ch]
45 *===---------------------------------------------------------------------===*/
46
47typedef enum { FIND, ENTER } ACTION;
48typedef char FULLEMPTY;
49const FULLEMPTY EMPTY = '\0';
50const FULLEMPTY FULL = '\1';
51
52const uint MAX_NUM_PROBES = 4;
53
54typedef struct PtrValueHashEntry_struct {
55 void* key;
56 Generic value;
57} PtrValueHashEntry;
58
59typedef struct PtrValueHashTable_struct {
60 PtrValueHashEntry* table;
61 FULLEMPTY* fullEmptyFlags;
62 Index capacity;
63 Index size;
64} PtrValueHashTable;
65
66
67extern Generic LookupOrInsertPtr(PtrValueHashTable* ptrTable,
68 void* ptr, ACTION action);
69
70extern void Insert(PtrValueHashTable* ptrTable, void* ptr, Generic value);
71
72extern void Delete(PtrValueHashTable* ptrTable, void* ptr);
73
74
75void
76InitializeTable(PtrValueHashTable* ptrTable, Index newSize)
77{
Vikram S. Adve0df8adc2003-07-08 18:42:44 +000078 ptrTable->table = (PtrValueHashEntry*) calloc(newSize,
Vikram S. Adve2df1f742002-05-19 15:49:58 +000079 sizeof(PtrValueHashEntry));
Vikram S. Adve0df8adc2003-07-08 18:42:44 +000080 ptrTable->fullEmptyFlags = (FULLEMPTY*) calloc(newSize, sizeof(FULLEMPTY));
Vikram S. Adve2df1f742002-05-19 15:49:58 +000081 ptrTable->capacity = newSize;
82 ptrTable->size = 0;
83}
84
85PtrValueHashTable*
86CreateTable(Index initialSize)
87{
88 PtrValueHashTable* ptrTable =
89 (PtrValueHashTable*) malloc(sizeof(PtrValueHashTable));
90 InitializeTable(ptrTable, initialSize);
91 return ptrTable;
92}
93
94void
95ReallocTable(PtrValueHashTable* ptrTable, Index newSize)
96{
Vikram S. Adve0df8adc2003-07-08 18:42:44 +000097 if (newSize <= ptrTable->capacity)
98 return;
99
100#ifndef NDEBUG
101 printf("\n***\n*** WARNING: REALLOCATING SPACE FOR POINTER HASH TABLE.\n");
Chris Lattner51577e52003-07-21 19:20:44 +0000102 printf("*** oldSize = %d, oldCapacity = %d\n***\n\n",
Vikram S. Adve0df8adc2003-07-08 18:42:44 +0000103 ptrTable->size, ptrTable->capacity);
104 printf("*** NEW SEQUENCE NUMBER FOR A POINTER WILL PROBABLY NOT MATCH ");
105 printf(" THE OLD ONE!\n***\n\n");
106#endif
107
108 unsigned int i;
109 PtrValueHashEntry* oldTable = ptrTable->table;
110 FULLEMPTY* oldFlags = ptrTable->fullEmptyFlags;
111 Index oldSize = ptrTable->size;
112 Index oldCapacity = ptrTable->capacity;
113
114 /* allocate the new storage and flags and re-insert the old entries */
115 InitializeTable(ptrTable, newSize);
116 memcpy(ptrTable->table, oldTable,
117 oldCapacity * sizeof(PtrValueHashEntry));
118 memcpy(ptrTable->fullEmptyFlags, oldFlags,
119 oldCapacity * sizeof(FULLEMPTY));
120 ptrTable->size = oldSize;
121
122#ifndef NDEBUG
123 for (i=0; i < oldCapacity; ++i) {
124 assert(ptrTable->fullEmptyFlags[i] == oldFlags[i]);
125 assert(ptrTable->table[i].key == oldTable[i].key);
126 assert(ptrTable->table[i].value == oldTable[i].value);
127 }
128#endif
Vikram S. Adve2df1f742002-05-19 15:49:58 +0000129
Vikram S. Adve0df8adc2003-07-08 18:42:44 +0000130 free(oldTable);
131 free(oldFlags);
Vikram S. Adve2df1f742002-05-19 15:49:58 +0000132}
133
134void
135DeleteTable(PtrValueHashTable* ptrTable)
136{
137 free(ptrTable->table);
138 free(ptrTable->fullEmptyFlags);
139 memset(ptrTable, '\0', sizeof(PtrValueHashTable));
140 free(ptrTable);
141}
142
143void
144InsertAtIndex(PtrValueHashTable* ptrTable, void* ptr, Generic value, Index index)
145{
146 assert(ptrTable->fullEmptyFlags[index] == EMPTY && "Slot is in use!");
147 ptrTable->table[index].key = ptr;
148 ptrTable->table[index].value = value;
149 ptrTable->fullEmptyFlags[index] = FULL;
150 ptrTable->size++;
151}
152
153void
154DeleteAtIndex(PtrValueHashTable* ptrTable, Index index)
155{
156 assert(ptrTable->fullEmptyFlags[index] == FULL && "Deleting empty slot!");
157 ptrTable->table[index].key = NULL;
158 ptrTable->table[index].value = (Generic) NULL;
159 ptrTable->fullEmptyFlags[index] = EMPTY;
160 ptrTable->size--;
161}
162
163Index
164FindIndex(PtrValueHashTable* ptrTable, void* ptr)
165{
166 uint numProbes = 1;
167 Index index = PointerHashFunc(ptr, ptrTable->capacity);
168 if (ptrTable->fullEmptyFlags[index] == FULL)
169 {
170 if (ptrTable->table[index].key == ptr)
171 return index;
172
173 /* First lookup failed on non-empty slot: probe further */
174 while (numProbes < MAX_NUM_PROBES)
175 {
176 index = PointerRehashFunc(index, ptrTable->capacity);
177 if (ptrTable->fullEmptyFlags[index] == EMPTY)
178 break;
179 else if (ptrTable->table[index].key == ptr)
180 return index;
181 ++numProbes;
182 }
183 }
184
185 /* Lookup failed: item is not in the table. */
186 /* If last slot is empty, use that slot. */
187 /* Otherwise, table must have been reallocated, so search again. */
188
189 if (numProbes == MAX_NUM_PROBES)
190 { /* table is too full: reallocate and search again */
191 ReallocTable(ptrTable, 1 + 2*ptrTable->capacity);
192 return FindIndex(ptrTable, ptr);
193 }
194 else
195 {
196 assert(ptrTable->fullEmptyFlags[index] == EMPTY &&
197 "Stopped before finding an empty slot and before MAX probes!");
198 return index;
199 }
200}
201
202Generic
203LookupOrInsertPtr(PtrValueHashTable* ptrTable, void* ptr, ACTION action)
204{
205 Index index = FindIndex(ptrTable, ptr);
206 if (ptrTable->fullEmptyFlags[index] == FULL &&
207 ptrTable->table[index].key == ptr)
208 return ptrTable->table[index].value;
209
210 /* Lookup failed: item is not in the table */
211 if (action != ENTER)
212 return (Generic) NULL;
213
214 /* Insert item into the table and return its index */
215 InsertAtIndex(ptrTable, ptr, (Generic) NULL, index);
216 return (Generic) NULL;
217}
218
219/* Returns NULL if the item is not found. */
220/* void* LookupPtr(PtrValueHashTable* ptrTable, void* ptr) */
221#define LookupPtr(ptrTable, ptr) \
222 LookupOrInsertPtr(ptrTable, ptr, FIND)
223
224void
225Insert(PtrValueHashTable* ptrTable, void* ptr, Generic value)
226{
227 Index index = FindIndex(ptrTable, ptr);
228 assert(ptrTable->fullEmptyFlags[index] == EMPTY &&
229 "ptr is already in the table: delete it first!");
230 InsertAtIndex(ptrTable, ptr, value, index);
231}
232
233void
234Delete(PtrValueHashTable* ptrTable, void* ptr)
235{
236 Index index = FindIndex(ptrTable, ptr);
237 if (ptrTable->fullEmptyFlags[index] == FULL &&
238 ptrTable->table[index].key == ptr)
239 {
240 DeleteAtIndex(ptrTable, index);
241 }
242}
243
244/*===---------------------------------------------------------------------=====
245 * RUNTIME ROUTINES TO MAP POINTERS TO SEQUENCE NUMBERS
246 *===---------------------------------------------------------------------===*/
247
248PtrValueHashTable* SequenceNumberTable = NULL;
Vikram S. Adve0df8adc2003-07-08 18:42:44 +0000249Index INITIAL_SIZE = 1 << 22;
Vikram S. Adve2df1f742002-05-19 15:49:58 +0000250
251#define MAX_NUM_SAVED 1024
252
253typedef struct PointerSet_struct {
254 char* savedPointers[MAX_NUM_SAVED]; /* 1024 alloca'd ptrs shd suffice */
255 unsigned int numSaved;
256 struct PointerSet_struct* nextOnStack; /* implement a cheap stack */
257} PointerSet;
258
259PointerSet* topOfStack = NULL;
260
261SequenceNumber
262HashPointerToSeqNum(char* ptr)
263{
264 static SequenceNumber count = 0;
265 SequenceNumber seqnum;
266 if (SequenceNumberTable == NULL) {
267 assert(MAX_NUM_PROBES < INITIAL_SIZE+1 && "Initial size too small");
268 SequenceNumberTable = CreateTable(INITIAL_SIZE);
269 }
270 seqnum = (SequenceNumber) LookupPtr(SequenceNumberTable, ptr);
271 if (seqnum == 0)
272 {
273 Insert(SequenceNumberTable, ptr, ++count);
274 seqnum = count;
275 }
276 return seqnum;
277}
278
279void
280ReleasePointerSeqNum(char* ptr)
281{ /* if a sequence number was assigned to this ptr, release it */
Vikram S. Adve2df1f742002-05-19 15:49:58 +0000282 if (SequenceNumberTable != NULL)
283 Delete(SequenceNumberTable, ptr);
284}
285
286void
287PushPointerSet()
288{
289 PointerSet* newSet = (PointerSet*) malloc(sizeof(PointerSet));
290 newSet->numSaved = 0;
291 newSet->nextOnStack = topOfStack;
292 topOfStack = newSet;
293}
294
295void
296PopPointerSet()
297{
298 PointerSet* oldSet;
299 assert(topOfStack != NULL && "popping from empty stack!");
300 oldSet = topOfStack;
301 topOfStack = oldSet->nextOnStack;
302 assert(oldSet->numSaved == 0);
303 free(oldSet);
304}
305
306/* free the pointers! */
307static void
308ReleaseRecordedPointers(char* savedPointers[MAX_NUM_SAVED],
309 unsigned int numSaved)
310{
311 unsigned int i;
312 for (i=0; i < topOfStack->numSaved; ++i)
313 ReleasePointerSeqNum(topOfStack->savedPointers[i]);
314}
315
316void
317ReleasePointersPopSet()
318{
319 ReleaseRecordedPointers(topOfStack->savedPointers, topOfStack->numSaved);
320 topOfStack->numSaved = 0;
321 PopPointerSet();
322}
323
324void
325RecordPointer(char* ptr)
326{ /* record pointers for release later */
327 if (topOfStack->numSaved == MAX_NUM_SAVED) {
328 printf("***\n*** WARNING: OUT OF ROOM FOR SAVED POINTERS."
329 " ALL POINTERS ARE BEING FREED.\n"
330 "*** THE SEQUENCE NUMBERS OF SAVED POINTERS WILL CHANGE!\n*** \n");
331 ReleaseRecordedPointers(topOfStack->savedPointers, topOfStack->numSaved);
332 topOfStack->numSaved = 0;
333 }
334 topOfStack->savedPointers[topOfStack->numSaved++] = ptr;
335}
336
337/*===---------------------------------------------------------------------=====
338 * TEST DRIVER FOR INSTRUMENTATION LIBRARY
339 *===---------------------------------------------------------------------===*/
340
341#ifndef TEST_INSTRLIB
342#undef TEST_INSTRLIB /* #define this to turn on by default */
343#endif
344
345#ifdef TEST_INSTRLIB
346int
347main(int argc, char** argv)
348{
349 int i, j;
350 int doRelease = 0;
351
352 INITIAL_SIZE = 5; /* start with small table to test realloc's*/
353
354 if (argc > 1 && ! strcmp(argv[1], "-r"))
355 {
356 PushPointerSet();
357 doRelease = 1;
358 }
359
360 for (i=0; i < argc; ++i)
361 for (j=0; argv[i][j]; ++j)
362 {
363 printf("Sequence number for argc[%d][%d] (%c) = Hash(%p) = %d\n",
364 i, j, argv[i][j], argv[i]+j, HashPointerToSeqNum(argv[i]+j));
365
366 if (doRelease)
367 RecordPointer(argv[i]+j);
368 }
369
370 if (doRelease)
371 ReleasePointersPopSet();
372
373 /* print sequence numbers out again to compare with (-r) and w/o release */
374 for (i=argc-1; i >= 0; --i)
375 for (j=0; argv[i][j]; ++j)
Vikram S. Advee04a2e02003-07-11 22:02:28 +0000376 printf("Sequence number for argc[%d][%d] (%c) = %d\n",
Vikram S. Adve2df1f742002-05-19 15:49:58 +0000377 i, j, argv[i][j], argv[i]+j, HashPointerToSeqNum(argv[i]+j));
378
379 return 0;
380}
381#endif