Add a hint about the infamous pn_Cmp_Lg/Ne mixup in the assertion message of verify_n...
[libfirm] / ir / ir / valueset.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @author    Michael Beck
23  * @brief     A value set, containing expression for values.
24  * @version   $Id$
25  */
26 #include "config.h"
27
28 #include "valueset.h"
29 #include "irnode_t.h"
30 #include "iropt_t.h"
31 #include "hashptr.h"
32
33 static ir_valueset_entry_t null_valueset_entry;
34
35 #undef DO_REHASH
36 #define HashSet                   ir_valueset_t
37 #define HashSetIterator           ir_valueset_iterator_t
38 #define ValueType                 ir_valueset_entry_t
39 #define NullValue                 null_valueset_entry
40 #define KeyType                   ir_node*
41 #define ConstKeyType              const ir_node*
42 #define GetKey(entry)             (entry).value
43 #define InitData(self,entry,key)  do { (entry).value = (key); (entry).list.next = NULL; (entry).list.prev = NULL; } while (0)
44 #define Hash(self,key)            ir_node_hash(key)
45 #define KeysEqual(self,key1,key2) (key1) == (key2)
46 #define SetRangeEmpty(ptr,size)   memset(ptr, 0, (size) * sizeof((ptr)[0]))
47 #define EntrySetEmpty(entry)      (entry).value = NULL
48 #define EntrySetDeleted(entry)    do { (entry).data.value = (ir_node*) -1; list_del(&(entry).data.list); } while (0)
49 #define EntryIsEmpty(entry)       ((entry).data.value == NULL)
50 #define EntryIsDeleted(entry)     ((entry).data.value == (ir_node*)-1)
51
52 #define hashset_init            ir_valueset_init
53 #define hashset_init_size       ir_valueset_init_size
54 #define hashset_destroy         ir_valueset_destroy
55 ir_valueset_entry_t *ir_valueset_insert_(ir_valueset_t *self, ir_node *value);
56 #define hashset_insert          ir_valueset_insert_
57 #define hashset_remove          ir_valueset_remove
58 ir_valueset_entry_t *ir_valueset_find_(const ir_valueset_t *self,
59                                        const ir_node *value);
60 #define hashset_find            ir_valueset_find_
61 #define hashset_size            ir_valueset_size
62
63 #define ADDITIONAL_INIT         INIT_LIST_HEAD(&self->elem_list); INIT_LIST_HEAD(&self->all_iters);
64 #define ADDITIONAL_TERM         INIT_LIST_HEAD(&self->elem_list); INIT_LIST_HEAD(&self->all_iters);
65
66 #define NO_ITERATOR
67 #define HAVE_OWN_RESIZE
68
69 #include "hashset.c"
70
71 /**
72  * Resize the hashset
73  * @internal
74  */
75 static void resize(HashSet *self, size_t new_size)
76 {
77         HashSetEntry *old_entries = self->entries;
78         HashSetEntry *new_entries;
79         list_head    list = self->elem_list;
80         ValueType    *entry;
81         int          res = 1;
82
83         /* allocate a new array with double size */
84         new_entries = Alloc(new_size);
85         SetRangeEmpty(new_entries, new_size);
86
87         /* use the new array */
88         self->entries      = new_entries;
89         self->num_buckets  = new_size;
90         self->num_elements = 0;
91         self->num_deleted  = 0;
92 #ifndef NDEBUG
93         self->entries_version++;
94 #endif
95         reset_thresholds(self);
96
97         assert(!list_empty(&self->elem_list));
98         list.next->prev = &list;
99         list.prev->next = &list;
100
101         /* reinsert all elements */
102         INIT_LIST_HEAD(&self->elem_list);
103         list_for_each_entry(ValueType, entry, &list, list) {
104                 res &= ir_valueset_insert(self, entry->value, entry->expr);
105         }
106         /* all re-inserted data must be new, if not, we found a node twice ... */
107         assert(res == 1);
108
109         /* now we can free the old array */
110         Free(old_entries);
111 }
112
113 int ir_valueset_insert(ir_valueset_t *valueset, ir_node *value, ir_node *expr)
114 {
115         ir_valueset_entry_t *entry = ir_valueset_insert_(valueset, value);
116
117         if (entry->list.next != NULL) {
118                 /* this value is already inserted, do nothing */
119                 return 0;
120         }
121
122         /* new element added */
123         entry->expr = expr;
124         list_add_tail(&entry->list, &valueset->elem_list);
125         return 1;
126 }
127
128 int ir_valueset_replace(ir_valueset_t *valueset, ir_node *value, ir_node *expr)
129 {
130         int res = 0;
131         ir_valueset_entry_t *entry = ir_valueset_insert_(valueset, value);
132
133         if (entry->expr != expr) {
134                 entry->expr = expr;
135                 res = 1;
136         }
137         if (entry->list.next == NULL) {
138                 /* we have added a new element */
139                 list_add_tail(&entry->list, &valueset->elem_list);
140                 return 1;
141         }
142         return res;
143 }
144
145 void *ir_valueset_lookup(const ir_valueset_t *valueset, const ir_node *value)
146 {
147         ir_valueset_entry_t *entry = ir_valueset_find_(valueset, value);
148         if (entry != NULL)
149                 return entry->expr;
150         return NULL;
151 }
152
153 void ir_valueset_iterator_init(ir_valueset_iterator_t *iterator,
154                                const ir_valueset_t *valueset)
155 {
156         iterator->iter     = valueset->elem_list.next;
157         iterator->valueset = valueset;
158 }
159
160 ir_node *ir_valueset_iterator_next(ir_valueset_iterator_t *iterator, ir_node **expr)
161 {
162         ir_valueset_entry_t *entry;
163
164         if (iterator->iter == &iterator->valueset->elem_list) {
165                 *expr = NULL;
166                 return NULL;
167         }
168
169         entry = list_entry(iterator->iter, ir_valueset_entry_t, list);
170         iterator->iter = iterator->iter->next;
171
172         *expr = entry->expr;
173         return entry->value;
174 }
175
176 void ir_valueset_remove_iterator(ir_valueset_t *valueset, ir_valueset_iterator_t *iterator)
177 {
178         ir_valueset_entry_t *rem = list_entry(iterator->iter->prev, ir_valueset_entry_t, list);
179
180         ir_valueset_remove(valueset, rem->value);
181 }