fix a bug and print predicate tree in xdot syntax
[c11tester.git] / funcnode.cc
1 #include "funcnode.h"
2 #include <fcntl.h>
3 #include "common.h"
4
5 FuncNode::FuncNode() :
6         predicate_tree_initialized(false),
7         func_inst_map(),
8         inst_list(),
9         entry_insts(),
10         thrd_read_map(),
11         predicate_tree_entry()
12 {}
13
14 /* Check whether FuncInst with the same type, position, and location
15  * as act has been added to func_inst_map or not. If so, return it;
16  * if not, add it and return it.
17  *
18  * @return FuncInst with the same type, position, and location as act */
19 FuncInst * FuncNode::get_or_add_inst(ModelAction *act)
20 {
21         ASSERT(act);
22         const char * position = act->get_position();
23
24         /* THREAD* actions, ATOMIC_LOCK, ATOMIC_TRYLOCK, and ATOMIC_UNLOCK
25          * actions are not tagged with their source line numbers
26          */
27         if (position == NULL)
28                 return NULL;
29
30         if ( func_inst_map.contains(position) ) {
31                 FuncInst * inst = func_inst_map.get(position);
32
33                 if (inst->get_type() != act->get_type() ) {
34                         // model_print("action with a different type occurs at line number %s\n", position);
35                         FuncInst * func_inst = inst->search_in_collision(act);
36
37                         if (func_inst != NULL) {
38                                 // return the FuncInst found in the collision list
39                                 return func_inst;
40                         }
41
42                         func_inst = new FuncInst(act, this);
43                         inst->get_collisions()->push_back(func_inst);
44                         inst_list.push_back(func_inst); // delete?
45
46                         return func_inst;
47                 }
48
49                 return inst;
50         }
51
52         FuncInst * func_inst = new FuncInst(act, this);
53
54         func_inst_map.put(position, func_inst);
55         inst_list.push_back(func_inst);
56
57         return func_inst;
58 }
59
60 void FuncNode::add_entry_inst(FuncInst * inst)
61 {
62         if (inst == NULL)
63                 return;
64
65         mllnode<FuncInst *> * it;
66         for (it = entry_insts.begin(); it != NULL; it = it->getNext()) {
67                 if (inst == it->getVal())
68                         return;
69         }
70
71         entry_insts.push_back(inst);
72 }
73
74 /**
75  * @brief Convert ModelAdtion list to FuncInst list 
76  * @param act_list A list of ModelActions
77  */
78 void FuncNode::update_tree(action_list_t * act_list)
79 {
80         if (act_list == NULL)
81                 return;
82         else if (act_list->size() == 0)
83                 return;
84
85         /* build inst_list from act_list for later processing */
86         func_inst_list_t inst_list;
87         func_inst_list_t read_inst_list;
88         HashTable<FuncInst *, uint64_t, uintptr_t, 4> read_val_map;
89
90         for (sllnode<ModelAction *> * it = act_list->begin(); it != NULL; it = it->getNext()) {
91                 ModelAction * act = it->getVal();
92                 FuncInst * func_inst = get_or_add_inst(act);
93
94                 if (func_inst == NULL)
95                         continue;
96
97                 inst_list.push_back(func_inst);
98
99 /*              if (!predicate_tree_initialized) {
100                         model_print("position: %s ", act->get_position());
101                         act->print();
102                 }
103 */
104
105                 if (func_inst->is_read()) {
106                         read_inst_list.push_back(func_inst);
107                         read_val_map.put(func_inst, act->get_reads_from_value());
108                 }
109         }
110
111         update_inst_tree(&inst_list);
112         init_predicate_tree(&read_inst_list, &read_val_map);
113 }
114
115 /** 
116  * @brief Link FuncInsts in inst_list  - add one FuncInst to another's predecessors and successors
117  * @param inst_list A list of FuncInsts
118  */
119 void FuncNode::update_inst_tree(func_inst_list_t * inst_list)
120 {
121         if (inst_list == NULL)
122                 return;
123         else if (inst_list->size() == 0)
124                 return;
125
126         /* start linking */
127         sllnode<FuncInst *>* it = inst_list->begin();
128         sllnode<FuncInst *>* prev;
129
130         /* add the first instruction to the list of entry insts */
131         FuncInst * entry_inst = it->getVal();
132         add_entry_inst(entry_inst);
133
134         it = it->getNext();
135         while (it != NULL) {
136                 prev = it->getPrev();
137
138                 FuncInst * prev_inst = prev->getVal();
139                 FuncInst * curr_inst = it->getVal();
140
141                 prev_inst->add_succ(curr_inst);
142                 curr_inst->add_pred(prev_inst);
143
144                 it = it->getNext();
145         }
146 }
147
148 /* @param tid thread id
149  * Store the values read by atomic read actions into thrd_read_map */
150 void FuncNode::store_read(ModelAction * act, uint32_t tid)
151 {
152         ASSERT(act);
153
154         void * location = act->get_location();
155         uint64_t read_from_val = act->get_reads_from_value();
156
157         /* resize and initialize */
158         uint32_t old_size = thrd_read_map.size();
159         if (old_size <= tid) {
160                 thrd_read_map.resize(tid + 1);
161                 for (uint32_t i = old_size; i < tid + 1;i++)
162                         thrd_read_map[i] = new read_map_t();
163         }
164
165         read_map_t * read_map = thrd_read_map[tid];
166         read_map->put(location, read_from_val);
167
168         /* Store the memory locations where atomic reads happen */
169         // read_locations.add(location);
170 }
171
172 uint64_t FuncNode::query_last_read(void * location, uint32_t tid)
173 {
174         if (thrd_read_map.size() <= tid)
175                 return 0xdeadbeef;
176
177         read_map_t * read_map = thrd_read_map[tid];
178
179         /* last read value not found */
180         if ( !read_map->contains(location) )
181                 return 0xdeadbeef;
182
183         uint64_t read_val = read_map->get(location);
184         return read_val;
185 }
186
187 /* @param tid thread id
188  * Reset read map for a thread. This function shall only be called
189  * when a thread exits a function
190  */
191 void FuncNode::clear_read_map(uint32_t tid)
192 {
193         if (thrd_read_map.size() <= tid)
194                 return;
195
196         thrd_read_map[tid]->reset();
197 }
198
199 void FuncNode::init_predicate_tree(func_inst_list_t * inst_list, HashTable<FuncInst *, uint64_t, uintptr_t, 4> * read_val_map)
200 {
201         if (inst_list == NULL || inst_list->size() == 0)
202                 return;
203
204         if (predicate_tree_initialized) {
205                 return;
206         }
207
208         predicate_tree_initialized = true;
209
210         // maybe restrict the size of hashtable to save calloc time
211         HashTable<void *, FuncInst *, uintptr_t, 4> loc_inst_map;
212
213         sllnode<FuncInst *> *it = inst_list->begin();
214         FuncInst * entry_inst = it->getVal();
215
216         /* entry instruction has no predicate expression */
217         Predicate * curr_pred = new Predicate(entry_inst);
218         predicate_tree_entry.add(curr_pred);
219         loc_inst_map.put(entry_inst->get_location(), entry_inst);
220
221         it = it->getNext();
222         while (it != NULL) {
223                 FuncInst * curr_inst = it->getVal();
224                 if ( loc_inst_map.contains(curr_inst->get_location()) ) {
225                         Predicate * new_pred1 = new Predicate(curr_inst);
226                         new_pred1->add_predicate(EQUALITY, curr_inst->get_location(), true);
227
228                         Predicate * new_pred2 = new Predicate(curr_inst);
229                         new_pred2->add_predicate(EQUALITY, curr_inst->get_location(), false);
230
231                         curr_pred->add_child(new_pred1);
232                         curr_pred->add_child(new_pred2);
233
234                         FuncInst * last_inst = loc_inst_map.get(curr_inst->get_location());
235
236                         uint64_t last_read = read_val_map->get(last_inst);
237                         if ( last_read == read_val_map->get(curr_inst) )
238                                 curr_pred = new_pred1;
239                         else
240                                 curr_pred = new_pred2;
241                 } else {
242                         Predicate * new_pred = new Predicate(curr_inst);
243                         curr_pred->add_child(new_pred);
244                         curr_pred = new_pred;
245                 }
246
247                 loc_inst_map.put(curr_inst->get_location(), curr_inst);
248
249                 it = it->getNext();
250         }
251
252         model_print("function %s\n", func_name);
253         print_predicate_tree();
254 }
255
256
257 void FuncNode::print_predicate_tree()
258 {
259         model_print("digraph function_%s {\n", func_name);
260         HSIterator<Predicate *, uintptr_t, 0, model_malloc, model_calloc, model_free> * it;
261         it = predicate_tree_entry.iterator();
262
263         while (it->hasNext()) {
264                 Predicate * p = it->next();
265                 p->print_pred_subtree();
266         }
267         model_print("}\n");     // end of graph
268 }
269
270 /* @param tid thread id
271  * Print the values read by the last read actions for each memory location
272  */
273 /*
274 void FuncNode::print_last_read(uint32_t tid)
275 {
276         ASSERT(thrd_read_map.size() > tid);
277         read_map_t * read_map = thrd_read_map[tid];
278
279         mllnode<void *> * it;
280         for (it = read_locations.begin();it != NULL;it=it->getNext()) {
281                 if ( !read_map->contains(it->getVal()) )
282                         break;
283
284                 uint64_t read_val = read_map->get(it->getVal());
285                 model_print("last read of thread %d at %p: 0x%x\n", tid, it->getVal(), read_val);
286         }
287 }
288 */