experiment with adding NULLITY predicate
[c11tester.git] / funcnode.cc
1 #include "funcnode.h"
2
3 FuncNode::FuncNode() :
4         predicate_tree_initialized(false),
5         predicate_tree_entry(new Predicate(NULL, true)),
6         func_inst_map(),
7         inst_list(),
8         entry_insts(),
9         thrd_read_map()
10 {}
11
12 /* Check whether FuncInst with the same type, position, and location
13  * as act has been added to func_inst_map or not. If not, add it.
14  *
15  * Note: currently, actions with the same position are filtered out by process_action,
16  * so the collision list of FuncInst is not used. May remove it later. 
17  */
18 void FuncNode::add_inst(ModelAction *act)
19 {
20         ASSERT(act);
21         const char * position = act->get_position();
22
23         /* THREAD* actions, ATOMIC_LOCK, ATOMIC_TRYLOCK, and ATOMIC_UNLOCK
24          * actions are not tagged with their source line numbers
25          */
26         if (position == NULL)
27                 return;
28
29         if ( func_inst_map.contains(position) ) {
30                 FuncInst * inst = func_inst_map.get(position);
31
32                 ASSERT(inst->get_type() == act->get_type());
33                 if (inst->get_location() != act->get_location())
34                         inst->not_single_location();
35
36                 return;
37         }
38
39         FuncInst * func_inst = new FuncInst(act, this);
40
41         func_inst_map.put(position, func_inst);
42         inst_list.push_back(func_inst);
43 }
44
45 /* Get the FuncInst with the same type, position, and location
46  * as act
47  *
48  * @return FuncInst with the same type, position, and location as act */
49 FuncInst * FuncNode::get_inst(ModelAction *act)
50 {
51         ASSERT(act);
52         const char * position = act->get_position();
53
54         /* THREAD* actions, ATOMIC_LOCK, ATOMIC_TRYLOCK, and ATOMIC_UNLOCK
55          * actions are not tagged with their source line numbers
56          */
57         if (position == NULL)
58                 return NULL;
59
60         FuncInst * inst = func_inst_map.get(position);
61         if (inst == NULL)
62                 return NULL;
63
64         action_type inst_type = inst->get_type();
65         action_type act_type = act->get_type();
66
67         // else if branch: an RMWRCAS action is converted to a RMW or READ action
68         if (inst_type == act_type)
69                 return inst;
70         else if (inst_type == ATOMIC_RMWRCAS &&
71                         (act_type == ATOMIC_RMW || act_type == ATOMIC_READ))
72                 return inst;
73
74         return NULL;
75 }
76
77
78 void FuncNode::add_entry_inst(FuncInst * inst)
79 {
80         if (inst == NULL)
81                 return;
82
83         mllnode<FuncInst *> * it;
84         for (it = entry_insts.begin(); it != NULL; it = it->getNext()) {
85                 if (inst == it->getVal())
86                         return;
87         }
88
89         entry_insts.push_back(inst);
90 }
91
92 /**
93  * @brief Convert ModelAdtion list to FuncInst list 
94  * @param act_list A list of ModelActions
95  */
96 void FuncNode::update_tree(action_list_t * act_list)
97 {
98         if (act_list == NULL)
99                 return;
100         else if (act_list->size() == 0)
101                 return;
102
103         /* build inst_list from act_list for later processing */
104         func_inst_list_t inst_list;
105         action_list_t read_act_list;
106
107         for (sllnode<ModelAction *> * it = act_list->begin(); it != NULL; it = it->getNext()) {
108                 ModelAction * act = it->getVal();
109                 FuncInst * func_inst = get_inst(act);
110
111                 if (func_inst == NULL)
112                         continue;
113
114                 inst_list.push_back(func_inst);
115
116 //              model_print("position: %s ", act->get_position());
117 //              act->print();
118
119                 if (func_inst->is_read())
120                         read_act_list.push_back(act);
121         }
122
123         model_print("function %s\n", func_name);
124         update_inst_tree(&inst_list);
125         update_predicate_tree(&read_act_list);
126         deep_update(predicate_tree_entry);
127
128         print_predicate_tree();
129 }
130
131 /** 
132  * @brief Link FuncInsts in inst_list  - add one FuncInst to another's predecessors and successors
133  * @param inst_list A list of FuncInsts
134  */
135 void FuncNode::update_inst_tree(func_inst_list_t * inst_list)
136 {
137         if (inst_list == NULL)
138                 return;
139         else if (inst_list->size() == 0)
140                 return;
141
142         /* start linking */
143         sllnode<FuncInst *>* it = inst_list->begin();
144         sllnode<FuncInst *>* prev;
145
146         /* add the first instruction to the list of entry insts */
147         FuncInst * entry_inst = it->getVal();
148         add_entry_inst(entry_inst);
149
150         it = it->getNext();
151         while (it != NULL) {
152                 prev = it->getPrev();
153
154                 FuncInst * prev_inst = prev->getVal();
155                 FuncInst * curr_inst = it->getVal();
156
157                 prev_inst->add_succ(curr_inst);
158                 curr_inst->add_pred(prev_inst);
159
160                 it = it->getNext();
161         }
162 }
163
164 /* @param tid thread id
165  * Store the values read by atomic read actions into thrd_read_map */
166 void FuncNode::store_read(ModelAction * act, uint32_t tid)
167 {
168         ASSERT(act);
169
170         void * location = act->get_location();
171         uint64_t read_from_val = act->get_reads_from_value();
172
173         /* resize and initialize */
174         uint32_t old_size = thrd_read_map.size();
175         if (old_size <= tid) {
176                 thrd_read_map.resize(tid + 1);
177                 for (uint32_t i = old_size; i < tid + 1;i++)
178                         thrd_read_map[i] = new read_map_t();
179         }
180
181         read_map_t * read_map = thrd_read_map[tid];
182         read_map->put(location, read_from_val);
183
184         /* Store the memory locations where atomic reads happen */
185         // read_locations.add(location);
186 }
187
188 uint64_t FuncNode::query_last_read(void * location, uint32_t tid)
189 {
190         if (thrd_read_map.size() <= tid)
191                 return VALUE_NONE;
192
193         read_map_t * read_map = thrd_read_map[tid];
194
195         /* last read value not found */
196         if ( !read_map->contains(location) )
197                 return VALUE_NONE;
198
199         uint64_t read_val = read_map->get(location);
200         return read_val;
201 }
202
203 /* @param tid thread id
204  * Reset read map for a thread. This function shall only be called
205  * when a thread exits a function
206  */
207 void FuncNode::clear_read_map(uint32_t tid)
208 {
209         if (thrd_read_map.size() <= tid)
210                 return;
211
212         thrd_read_map[tid]->reset();
213 }
214
215 void FuncNode::update_predicate_tree(action_list_t * act_list)
216 {
217         if (act_list == NULL || act_list->size() == 0)
218                 return;
219 /*
220         if (predicate_tree_initialized) {
221                 return;
222         }
223         predicate_tree_initialized = true;
224 */
225         /* map a FuncInst to the parent of its predicate */
226         HashTable<FuncInst *, Predicate *, uintptr_t, 0> inst_pred_map(128);
227         HashTable<void *, ModelAction *, uintptr_t, 0> loc_act_map(128);
228
229         sllnode<ModelAction *> *it = act_list->begin();
230         Predicate * curr_pred = predicate_tree_entry;
231
232         while (it != NULL) {
233                 ModelAction * next_act = it->getVal();
234                 FuncInst * next_inst = get_inst(next_act);
235                 Predicate * old_pred = curr_pred;
236
237                 bool branch_found = follow_branch(&curr_pred, next_inst, next_act, &loc_act_map);
238
239                 // check back edges
240                 if (!branch_found) {
241                         Predicate * back_pred = curr_pred->get_backedge();
242                         if (back_pred != NULL) {
243                                 curr_pred = back_pred;
244                                 continue;
245                         }
246
247                         if (inst_pred_map.contains(next_inst)) {
248                                 back_pred = inst_pred_map.get(next_inst);
249                                 curr_pred->set_backedge(back_pred);
250                                 curr_pred = back_pred;
251                                 continue;
252                         }
253                 }
254
255                 if (!inst_pred_map.contains(next_inst))
256                         inst_pred_map.put(next_inst, old_pred);
257
258                 if (!branch_found) {
259                         if ( loc_act_map.contains(next_act->get_location()) ) {
260                                 Predicate * new_pred1 = new Predicate(next_inst);
261                                 new_pred1->add_predicate(EQUALITY, next_act->get_location(), true);
262
263                                 Predicate * new_pred2 = new Predicate(next_inst);
264                                 new_pred2->add_predicate(EQUALITY, next_act->get_location(), false);
265
266                                 curr_pred->add_child(new_pred1);
267                                 curr_pred->add_child(new_pred2);
268                                 new_pred1->set_parent(curr_pred);
269                                 new_pred2->set_parent(curr_pred);
270
271                                 ModelAction * last_act = loc_act_map.get(next_act->get_location());
272                                 uint64_t last_read = last_act->get_reads_from_value();
273                                 uint64_t next_read = next_act->get_reads_from_value();
274
275                                 if ( last_read == next_read )
276                                         curr_pred = new_pred1;
277                                 else
278                                         curr_pred = new_pred2;
279                         } else {
280                                 Predicate * new_pred = new Predicate(next_inst);
281                                 curr_pred->add_child(new_pred);
282                                 new_pred->set_parent(curr_pred);
283
284                                 curr_pred = new_pred;
285                         }
286                 }
287
288                 loc_act_map.put(next_act->get_location(), next_act);
289                 it = it->getNext();
290         }
291 }
292
293 void FuncNode::deep_update(Predicate * curr_pred)
294 {
295         FuncInst * func_inst = curr_pred->get_func_inst();
296         if (func_inst != NULL && !func_inst->is_single_location()) {
297                 bool has_null_pred = false;
298                 PredExprSet * pred_expressions = curr_pred->get_pred_expressions();
299                 PredExprSetIter * pred_expr_it = pred_expressions->iterator();
300                 while (pred_expr_it->hasNext()) {
301                         pred_expr * pred_expression = pred_expr_it->next();
302                         if (pred_expression->token == NULLITY) {
303                                 has_null_pred = true;
304                                 break;
305                         }
306                 }
307
308                 if (!has_null_pred) {
309 //                      func_inst->print();
310                         Predicate * parent = curr_pred->get_parent();
311                         curr_pred->add_predicate(NULLITY, NULL, 0);
312
313                         Predicate * another_branch = new Predicate(func_inst);
314                         another_branch->add_predicate(NULLITY, NULL, 1);
315                         parent->add_child(another_branch);
316 //                      another_branch.add_children(i);
317                 }
318         }
319
320         ModelVector<Predicate *> * branches = curr_pred->get_children();
321         for (uint i = 0; i < branches->size(); i++) {
322                 Predicate * branch = (*branches)[i];
323                 deep_update(branch);
324         }
325 }
326
327 /* Given curr_pred and next_inst, find the branch following curr_pred that contains next_inst and the correct predicate
328  * @return true if branch found, false otherwise.
329  */
330 bool FuncNode::follow_branch(Predicate ** curr_pred, FuncInst * next_inst, ModelAction * next_act,
331         HashTable<void *, ModelAction *, uintptr_t, 0> * loc_act_map)
332 {
333         /* check if a branch with func_inst and corresponding predicate exists */
334         bool branch_found = false;
335         ModelVector<Predicate *> * branches = (*curr_pred)->get_children();
336         for (uint i = 0; i < branches->size(); i++) {
337                 Predicate * branch = (*branches)[i];
338                 if (branch->get_func_inst() != next_inst)
339                         continue;
340
341                 PredExprSet * pred_expressions = branch->get_pred_expressions();
342
343                 /* no predicate, follow the only branch */
344                 if (pred_expressions->getSize() == 0) {
345                         *curr_pred = branch;
346                         branch_found = true;
347                         break;
348                 }
349
350                 PredExprSetIter * pred_expr_it = pred_expressions->iterator();
351                 while (pred_expr_it->hasNext()) {
352                         pred_expr * pred_expression = pred_expr_it->next();
353                         uint64_t last_read, next_read;
354                         ModelAction * last_act;
355                         bool equality;
356
357                         switch(pred_expression->token) {
358                                 case EQUALITY:
359                                         last_act = loc_act_map->get(next_act->get_location());
360                                         last_read = last_act->get_reads_from_value();
361                                         next_read = next_act->get_reads_from_value();
362
363                                         equality = (last_read == next_read);
364                                         if (equality == pred_expression->value) {
365                                                 *curr_pred = branch;
366 //                                              model_print("predicate: token: %d, location: %p, value: %d - ", pred_expression->token, pred_expression->location, pred_expression->value); next_inst->print();
367                                                 branch_found = true;
368                                         }
369                                         break;
370                                 case NULLITY:
371                                         next_read = next_act->get_reads_from_value();
372                                         equality = ((void*)next_read == NULL);
373                                         //model_print("%s ", next_act->get_position()); next_act->print();
374                                         if (equality == pred_expression->value) {
375                                                 *curr_pred = branch;
376                                                 branch_found = true;
377                                         }
378                                         break;
379                                 default:
380                                         model_print("unkown predicate token\n");
381                                         break;
382                         }
383                 }
384
385         }
386
387         return branch_found;
388 }
389
390 void FuncNode::print_predicate_tree()
391 {
392         model_print("digraph function_%s {\n", func_name);
393         predicate_tree_entry->print_pred_subtree();
394         model_print("}\n");     // end of graph
395 }
396
397 /* @param tid thread id
398  * Print the values read by the last read actions for each memory location
399  */
400 /*
401 void FuncNode::print_last_read(uint32_t tid)
402 {
403         ASSERT(thrd_read_map.size() > tid);
404         read_map_t * read_map = thrd_read_map[tid];
405
406         mllnode<void *> * it;
407         for (it = read_locations.begin();it != NULL;it=it->getNext()) {
408                 if ( !read_map->contains(it->getVal()) )
409                         break;
410
411                 uint64_t read_val = read_map->get(it->getVal());
412                 model_print("last read of thread %d at %p: 0x%x\n", tid, it->getVal(), read_val);
413         }
414 }
415 */