1 /* Copyright (c) 2015 Regents of the University of California
3 * Author: Brian Demsky <bdemsky@uci.edu>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
11 #include "mcexecution.h"
12 #include "constraint.h"
13 #include "branchrecord.h"
14 #include "functionrecord.h"
15 #include "equalsrecord.h"
16 #include "storeloadset.h"
18 #include "schedulebuilder.h"
23 #include "inc_solver.h"
28 gettimeofday(&tv, NULL);
29 return tv.tv_sec*1000000+tv.tv_usec;
32 ConstGen::ConstGen(MCExecution *e) :
33 storeloadtable(new StoreLoadSetHashTable()),
34 loadtable(new LoadHashTable()),
36 workstack(new ModelVector<EPRecord *>()),
37 threadactions(new ModelVector<ModelVector<EPRecord *> *>()),
38 rpt(new RecPairTable()),
40 goalset(new ModelVector<Constraint *>()),
41 yieldlist(new ModelVector<EPRecord *>()),
43 vars(new ModelVector<Constraint *>()),
44 branchtable(new BranchTable()),
45 functiontable(new FunctionTable()),
46 equalstable(new EqualsTable()),
47 schedulebuilder(new ScheduleBuilder(e, this)),
48 nonlocaltrans(new RecordSet()),
49 incompleteexploredbranch(new RecordSet()),
50 execcondtable(new LoadHashTable()),
52 rectoint(new RecToIntTable()),
53 yieldtable(new RecToConsTable()),
56 has_untaken_branches(false)
59 curr_stat=new MC_Stat();
61 curr_stat->was_incremental=false;
62 curr_stat->was_sat=true;
65 stats=new ModelVector<struct MC_Stat *>();
69 ConstGen::~ConstGen() {
73 for(uint i=0;i<vars->size();i++) {
74 Constraint *var=(*vars)[i];
75 Constraint *notvar=var->neg;
80 delete storeloadtable;
91 delete schedulebuilder;
93 delete incompleteexploredbranch;
99 void resetstoreloadtable(StoreLoadSetHashTable * storeloadtable) {
100 for(uint i=0;i<storeloadtable->capacity;i++) {
101 struct hashlistnode<const void *, StoreLoadSet *> * ptr=&storeloadtable->table[i];
102 if (ptr->val != NULL) {
103 if (ptr->val->removeAddress(ptr->key))
110 if (storeloadtable->zero != NULL) {
111 if (storeloadtable->zero->val->removeAddress(storeloadtable->zero->key)) {
112 delete storeloadtable->zero->val;
115 model_free(storeloadtable->zero);
116 storeloadtable->zero = NULL;
118 storeloadtable->size = 0;
121 void ConstGen::reset() {
122 for(uint i=0;i<threadactions->size();i++) {
123 delete (*threadactions)[i];
125 if (goalvararray != NULL) {
126 model_free(goalvararray);
129 functiontable->resetanddelete();
130 equalstable->resetanddelete();
131 branchtable->resetanddelete();
132 loadtable->resetanddelete();
133 execcondtable->resetanddelete();
134 rpt->resetanddelete();
135 resetstoreloadtable(storeloadtable);
136 nonlocaltrans->reset();
137 incompleteexploredbranch->reset();
138 threadactions->clear();
145 has_untaken_branches=false;
148 void ConstGen::translateGoals() {
149 int size=goalset->size();
150 goalvararray=(Constraint **) model_malloc(size*sizeof(Constraint *));
152 for(int i=0;i<size;i++) {
153 Constraint *goal=(*goalset)[i];
154 goalvararray[i]=getNewVar();
155 addConstraint(new Constraint(OR, goalvararray[i]->negate(), goal));
157 Constraint *atleastonegoal=new Constraint(OR, size, goalvararray);
158 ADDCONSTRAINT(atleastonegoal, "atleastonegoal");
161 bool ConstGen::canReuseEncoding() {
164 Constraint *array[goalset->size()];
165 int remaininggoals=0;
167 //Zero out the achieved goals
168 for(uint i=0;i<goalset->size();i++) {
169 Constraint *var=goalvararray[i];
171 array[remaininggoals++]=var;
174 if (remaininggoals == 0)
176 Constraint *atleastonegoal=new Constraint(OR, remaininggoals, array);
177 ADDCONSTRAINT(atleastonegoal, "atleastonegoal");
178 solver->finishedClauses();
179 clock_t start=myclock();
180 bool *solution=runSolver();
181 clock_t finish=myclock();
183 if (curr_stat != NULL)
184 stats->push_back(curr_stat);
185 curr_stat=new MC_Stat();
186 curr_stat->time=finish-start;
187 curr_stat->was_incremental=true;
188 curr_stat->was_sat=(solution!=NULL);
192 model_print("start %lu, finish %lu\n", start,finish);
193 model_print("Incremental time = %12.6f\n", ((double)(finish-start))/1000000);
195 if (solution==NULL) {
199 //Zero out the achieved goals
200 for(uint i=0;i<goalset->size();i++) {
201 Constraint *var=goalvararray[i];
203 if (solution[var->getVar()]) {
204 //if (goalvararray[i] != NULL)
205 //model_print("SAT clearing goal %d.\n", i);
207 goalvararray[i]=NULL;
212 schedulebuilder->buildSchedule(solution);
213 model_free(solution);
218 bool ConstGen::process() {
219 #ifdef DUMP_EVENT_GRAPHS
223 if (solver != NULL) {
228 solver=new IncrementalSolver();
231 genTransOrderConstraints();
233 genTSOTransOrderConstraints();
237 if (goalset->size()==0) {
239 stats->push_back(curr_stat);
240 for(uint i=0;i<stats->size();i++) {
241 struct MC_Stat *s=(*stats)[i];
242 model_print("time=%lld fgoals=%d bgoals=%d incremental=%d sat=%d\n", s->time, s->fgoals, s->bgoals, s->was_incremental, s->was_sat);
245 model_print("No goals, done\n");
251 if (model->params.branches && !has_untaken_branches) {
257 solver->finishedClauses();
259 //Freeze the goal variables
260 for(uint i=0;i<goalset->size();i++) {
261 Constraint *var=goalvararray[i];
262 solver->freeze(var->getVar());
265 clock_t start=myclock();
266 bool *solution=runSolver();
267 clock_t finish=myclock();
269 if (curr_stat != NULL)
270 stats->push_back(curr_stat);
271 curr_stat=new MC_Stat();
272 curr_stat->time=finish-start;
273 curr_stat->was_incremental=false;
274 curr_stat->was_sat=(solution!=NULL);
278 if (solution == NULL) {
279 stats->push_back(curr_stat);
280 for(uint i=0;i<stats->size();i++) {
281 struct MC_Stat *s=(*stats)[i];
282 model_print("time=%lld fgoals=%d bgoals=%d incremental=%d sat=%d\n", s->time, s->fgoals, s->bgoals, s->was_incremental, s->was_sat);
288 model_print("start %lu, finish %lu\n", start,finish);
289 model_print("Initial time = %12.6f\n", ((double)(finish-start))/1000000);
292 if (solution==NULL) {
298 //Zero out the achieved goals
299 for(uint i=0;i<goalset->size();i++) {
300 Constraint *var=goalvararray[i];
302 if (solution[var->getVar()]) {
303 //if (goalvararray[i] != NULL)
304 // model_print("SAT clearing goal %d.\n", i);
305 goalvararray[i]=NULL;
310 schedulebuilder->buildSchedule(solution);
311 model_free(solution);
315 void ConstGen::printEventGraph() {
317 sprintf(buffer, "eventgraph%u.dot",schedule_graph);
319 int file=open(buffer,O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
320 model_dprintf(file, "digraph eventgraph {\n");
322 EPRecord *first=execution->getEPRecord(MCID_FIRST);
323 printRecord(first, file);
324 while(!workstack->empty()) {
325 EPRecord *record=workstack->back();
326 workstack->pop_back();
327 printRecord(record, file);
330 model_dprintf(file, "}\n");
334 void ConstGen::doPrint(EPRecord *record, int file) {
335 model_dprintf(file, "%lu[label=\"",(uintptr_t)record);
337 model_dprintf(file, "\"];\n");
338 if (record->getNextRecord()!=NULL)
339 model_dprintf(file, "%lu->%lu;\n", (uintptr_t) record, (uintptr_t) record->getNextRecord());
341 if (record->getChildRecord()!=NULL)
342 model_dprintf(file, "%lu->%lu[color=red];\n", (uintptr_t) record, (uintptr_t) record->getChildRecord());
345 void ConstGen::printRecord(EPRecord *record, int file) {
347 doPrint(record,file);
349 if (record->getType()==LOOPENTER) {
350 workstack->push_back(record->getNextRecord());
351 workstack->push_back(record->getChildRecord());
354 if (record->getChildRecord()!=NULL) {
355 workstack->push_back(record->getChildRecord());
357 if (record->getType()==NONLOCALTRANS) {
360 if (record->getType()==LOOPEXIT) {
363 if (record->getType()==BRANCHDIR) {
364 EPRecord *next=record->getNextRecord();
366 workstack->push_back(next);
367 for(uint i=0;i<record->numValues();i++) {
368 EPValue *branchdir=record->getValue(i);
370 //Could have an empty branch, so make sure the branch actually
372 if (branchdir->getFirstRecord()!=NULL) {
373 workstack->push_back(branchdir->getFirstRecord());
374 model_dprintf(file, "%lu->%lu[color=blue];\n", (uintptr_t) record, (uintptr_t) branchdir->getFirstRecord());
379 record=record->getNextRecord();
380 } while(record!=NULL);
384 /* This function traverses a thread's graph in execution order. */
386 void ConstGen::traverse(bool initial) {
387 EPRecord *first=execution->getEPRecord(MCID_FIRST);
388 traverseRecord(first, initial);
389 while(!workstack->empty()) {
390 EPRecord *record=workstack->back();
391 workstack->pop_back();
392 traverseRecord(record, initial);
396 /** This method looks for all other memory operations that could
397 potentially share a location, and build partitions of memory
398 locations such that all memory locations that can share the same
399 address are in the same group.
401 These memory operations should share an encoding of addresses and
405 void ConstGen::groupMemoryOperations(EPRecord *op) {
406 /** Handle our first address */
407 IntHashSet *addrset=op->getSet(VC_ADDRINDEX);
408 IntIterator *ait=addrset->iterator();
410 void *iaddr=(void *) ait->next();
411 StoreLoadSet *isls=storeloadtable->get(iaddr);
413 isls=new StoreLoadSet();
414 storeloadtable->put(iaddr, isls);
418 while(ait->hasNext()) {
419 void *addr=(void *)ait->next();
420 StoreLoadSet *sls=storeloadtable->get(addr);
422 storeloadtable->put(addr, isls);
423 } else if (sls!=isls) {
425 mergeSets(isls, sls);
432 RecordSet * ConstGen::computeConflictSet(EPRecord *store, EPRecord *load, RecordSet * baseset) {
433 //See if we can determine addresses that store/load may use
434 IntIterator * storeaddr=store->getSet(VC_ADDRINDEX)->iterator();
435 int numaddr=0;void *commonaddr=NULL;
436 while(storeaddr->hasNext()) {
437 void *addr=(void *) storeaddr->next();
438 if (load->getSet(VC_ADDRINDEX)->contains((uint64_t)addr)) {
449 RecordSet *srscopy=baseset->copy();
450 RecordIterator *sri=srscopy->iterator();
451 while(sri->hasNext()) {
452 bool pruneconflictstore=false;
453 EPRecord *conflictstore=sri->next();
454 bool conflictafterstore=getOrderConstraint(store,conflictstore)->isTrue();
455 bool conflictbeforeload=getOrderConstraint(conflictstore,load)->isTrue();
457 if (conflictafterstore) {
458 RecordIterator *sricheck=srscopy->iterator();
459 while(sricheck->hasNext()) {
460 EPRecord *checkstore=sricheck->next();
461 bool checkafterstore=getOrderConstraint(store, checkstore)->isTrue();
462 if (!checkafterstore)
464 bool checkbeforeconflict=getOrderConstraint(checkstore,conflictstore)->isTrue();
465 if (!checkbeforeconflict)
468 //See if the checkstore must store to the relevant address
469 IntHashSet * storeaddr=checkstore->getSet(VC_ADDRINDEX);
471 if (storeaddr->getSize()!=1 || !storeaddr->contains((uint64_t)commonaddr))
475 if (subsumesExecutionConstraint(checkstore, conflictstore)) {
476 pruneconflictstore=true;
483 if (conflictbeforeload && !pruneconflictstore) {
484 RecordIterator *sricheck=srscopy->iterator();
485 while(sricheck->hasNext()) {
486 EPRecord *checkstore=sricheck->next();
488 bool checkafterconflict=getOrderConstraint(conflictstore, checkstore)->isTrue();
489 if (!checkafterconflict)
492 bool checkbeforeload=getOrderConstraint(checkstore, load)->isTrue();
493 if (!checkbeforeload)
496 //See if the checkstore must store to the relevant address
497 IntHashSet * storeaddr=checkstore->getSet(VC_ADDRINDEX);
498 if (storeaddr->getSize()!=1 || !storeaddr->contains((uint64_t)commonaddr))
502 if (subsumesExecutionConstraint(checkstore, conflictstore)) {
503 pruneconflictstore=true;
509 if (pruneconflictstore) {
510 //This store is redundant
520 /** This method returns all stores that a load may read from. */
522 RecordSet * ConstGen::getMayReadFromSet(EPRecord *load) {
523 if (load->getSet(VC_ADDRINDEX)->getSize()==1)
524 return getMayReadFromSetOpt(load);
526 RecordSet *srs=loadtable->get(load);
527 ExecPoint *epload=load->getEP();
528 thread_id_t loadtid=epload->get_tid();
531 loadtable->put(load, srs);
533 IntHashSet *addrset=load->getSet(VC_ADDRINDEX);
534 IntIterator *ait=addrset->iterator();
536 while(ait->hasNext()) {
537 void *addr=(void *)ait->next();
538 RecordSet *rs=execution->getStoreTable(addr);
542 RecordIterator * rit=rs->iterator();
543 while(rit->hasNext()) {
544 EPRecord *rec=rit->next();
545 ExecPoint *epstore=rec->getEP();
546 thread_id_t storetid=epstore->get_tid();
547 if (storetid != loadtid ||
548 epstore->compare(epload) == CR_AFTER)
559 RecordSet * ConstGen::getMayReadFromSetOpt(EPRecord *load) {
560 RecordSet *srs=loadtable->get(load);
561 ExecPoint *epload=load->getEP();
562 thread_id_t loadtid=epload->get_tid();
565 loadtable->put(load, srs);
567 IntHashSet *addrset=load->getSet(VC_ADDRINDEX);
568 IntIterator *ait=addrset->iterator();
569 void *addr=(void *)ait->next();
572 RecordSet *rs=execution->getStoreTable(addr);
573 RecordIterator * rit=rs->iterator();
574 ExecPoint *latest=NULL;
575 while(rit->hasNext()) {
576 EPRecord *store=rit->next();
577 ExecPoint *epstore=store->getEP();
578 thread_id_t storetid=epstore->get_tid();
579 if (storetid == loadtid && isAlwaysExecuted(store) &&
580 store->getSet(VC_ADDRINDEX)->getSize()==1 &&
581 epstore->compare(epload) == CR_AFTER &&
582 (latest==NULL || latest->compare(epstore) == CR_AFTER)) {
588 while(rit->hasNext()) {
589 EPRecord *store=rit->next();
590 ExecPoint *epstore=store->getEP();
591 thread_id_t storetid=epstore->get_tid();
592 if (storetid == loadtid) {
593 if (epstore->compare(epload) == CR_AFTER &&
594 (latest==NULL || epstore->compare(latest) != CR_AFTER))
605 /** This function merges two recordsets and updates the storeloadtable
608 void ConstGen::mergeSets(StoreLoadSet *to, StoreLoadSet *from) {
609 RecordIterator * sri=from->iterator();
610 while(sri->hasNext()) {
611 EPRecord *rec=sri->next();
613 IntHashSet *addrset=rec->getSet(VC_ADDRINDEX);
614 IntIterator *ait=addrset->iterator();
615 while(ait->hasNext()) {
616 void *addr=(void *)ait->next();
617 storeloadtable->put(addr, to);
626 /** This function creates ordering variables between stores and loads
627 * in same thread for TSO. */
629 void ConstGen::insertTSOAction(EPRecord *load) {
630 if (load->getType() != LOAD)
632 ExecPoint *load_ep=load->getEP();
633 thread_id_t tid=load_ep->get_tid();
634 uint thread=id_to_int(tid);
635 ModelVector<EPRecord *> * vector=(*threadactions)[thread];
636 uint j=vector->size()-1;
638 EPRecord *oldrec=(*vector)[--j];
639 EventType oldrec_t=oldrec->getType();
641 if (((oldrec_t == RMW) || (oldrec_t==FENCE)) &&
642 isAlwaysExecuted(oldrec)) {
644 } else if (oldrec_t == STORE) {
645 /* Only generate variables for things that can actually both run */
647 createOrderConstraint(oldrec, load);
652 void ConstGen::genTSOTransOrderConstraints() {
653 for(uint t1=0;t1<threadactions->size();t1++) {
654 ModelVector<EPRecord *> *tvec=(*threadactions)[t1];
655 uint size=tvec->size();
656 EPRecord *laststore=NULL;
657 for(uint store_i=0;store_i<size;store_i++) {
658 EPRecord *store=(*tvec)[store_i];
659 EventType store_t=store->getType();
660 if (store_t != STORE)
662 EPRecord *lastload=NULL;
663 for(uint load_i=store_i+1;load_i<size;load_i++) {
664 EPRecord *rec=(*tvec)[store_i];
665 //Hit fence, don't need more stuff
666 EventType rec_t=rec->getType();
667 if (((rec_t == RMW) || (rec_t == FENCE)) &&
668 isAlwaysExecuted(rec))
672 if (laststore != NULL) {
673 Constraint * storeload=getOrderConstraint(store, rec);
674 Constraint * earlystoreload=getOrderConstraint(laststore, rec);
675 Constraint * c=new Constraint(IMPLIES, storeload, earlystoreload);
676 ADDCONSTRAINT(c, "earlystore");
678 if (lastload != NULL) {
679 Constraint * storeearlyload=getOrderConstraint(store, lastload);
680 Constraint * storeload=getOrderConstraint(store, rec);
681 Constraint * c=new Constraint(IMPLIES, storeearlyload, storeload);
682 ADDCONSTRAINT(c, "earlyload");
692 /** This function creates ordering constraints to implement SC for
693 memory operations. */
695 void ConstGen::insertAction(EPRecord *record) {
696 thread_id_t tid=record->getEP()->get_tid();
697 uint thread=id_to_int(tid);
698 if (threadactions->size()<=thread) {
699 uint oldsize=threadactions->size();
700 threadactions->resize(thread+1);
701 for(;oldsize<=thread;oldsize++) {
702 (*threadactions)[oldsize]=new ModelVector<EPRecord *>();
706 (*threadactions)[thread]->push_back(record);
708 for(uint i=0;i<threadactions->size();i++) {
711 ModelVector<EPRecord *> * vector=(*threadactions)[i];
712 for(uint j=0;j<vector->size();j++) {
713 EPRecord *oldrec=(*vector)[j];
714 createOrderConstraint(oldrec, record);
718 insertTSOAction(record);
722 void ConstGen::genTransOrderConstraints() {
723 for(uint t1=0;t1<threadactions->size();t1++) {
724 ModelVector<EPRecord *> *t1vec=(*threadactions)[t1];
725 for(uint t2=0;t2<t1;t2++) {
726 ModelVector<EPRecord *> *t2vec=(*threadactions)[t2];
727 genTransOrderConstraints(t1vec, t2vec);
728 genTransOrderConstraints(t2vec, t1vec);
729 for(uint t3=0;t3<t2;t3++) {
730 ModelVector<EPRecord *> *t3vec=(*threadactions)[t3];
731 genTransOrderConstraints(t1vec, t2vec, t3vec);
737 void ConstGen::genTransOrderConstraints(ModelVector<EPRecord *> * t1vec, ModelVector<EPRecord *> *t2vec) {
738 for(uint t1i=0;t1i<t1vec->size();t1i++) {
739 EPRecord *t1rec=(*t1vec)[t1i];
740 for(uint t2i=0;t2i<t2vec->size();t2i++) {
741 EPRecord *t2rec=(*t2vec)[t2i];
743 /* Note: One only really needs to generate the first constraint
744 in the first loop and the last constraint in the last loop.
745 I tried this and performance suffered on linuxrwlocks and
746 linuxlocks at the current time. BD - August 2014*/
747 Constraint *c21=getOrderConstraint(t2rec, t1rec);
749 /* short circuit for the trivial case */
753 for(uint t3i=t2i+1;t3i<t2vec->size();t3i++) {
754 EPRecord *t3rec=(*t2vec)[t3i];
755 Constraint *c13=getOrderConstraint(t1rec, t3rec);
757 Constraint *c32=getOrderConstraint(t3rec, t2rec);
758 if (!c32->isFalse()) {
759 //Have a store->load that could be reordered, need to generate other constraint
760 Constraint *c12=getOrderConstraint(t1rec, t2rec);
761 Constraint *c23=getOrderConstraint(t2rec, t3rec);
762 Constraint *c31=getOrderConstraint(t3rec, t1rec);
763 Constraint *slarray[] = {c31, c23, c12};
764 Constraint * intradelayedstore=new Constraint(OR, 3, slarray);
765 ADDCONSTRAINT(intradelayedstore, "intradelayedstore");
767 Constraint * array[]={c21, c32, c13};
768 Constraint *intratransorder=new Constraint(OR, 3, array);
770 Constraint *intratransorder=new Constraint(OR, c21, c13);
772 ADDCONSTRAINT(intratransorder,"intratransorder");
775 for(uint t0i=0;t0i<t1i;t0i++) {
776 EPRecord *t0rec=(*t1vec)[t0i];
777 Constraint *c02=getOrderConstraint(t0rec, t2rec);
779 Constraint *c10=getOrderConstraint(t1rec, t0rec);
781 if (!c10->isFalse()) {
782 //Have a store->load that could be reordered, need to generate other constraint
783 Constraint *c01=getOrderConstraint(t0rec, t1rec);
784 Constraint *c12=getOrderConstraint(t1rec, t2rec);
785 Constraint *c20=getOrderConstraint(t2rec, t0rec);
786 Constraint *slarray[] = {c01, c12, c20};
787 Constraint * intradelayedstore=new Constraint(OR, 3, slarray);
788 ADDCONSTRAINT(intradelayedstore, "intradelayedstore");
790 Constraint * array[]={c10, c21, c02};
791 Constraint *intratransorder=new Constraint(OR, 3, array);
793 Constraint *intratransorder=new Constraint(OR, c21, c02);
795 ADDCONSTRAINT(intratransorder,"intratransorder");
802 void ConstGen::genTransOrderConstraints(ModelVector<EPRecord *> * t1vec, ModelVector<EPRecord *> *t2vec, ModelVector<EPRecord *> * t3vec) {
803 for(uint t1i=0;t1i<t1vec->size();t1i++) {
804 EPRecord *t1rec=(*t1vec)[t1i];
805 for(uint t2i=0;t2i<t2vec->size();t2i++) {
806 EPRecord *t2rec=(*t2vec)[t2i];
807 for(uint t3i=0;t3i<t3vec->size();t3i++) {
808 EPRecord *t3rec=(*t3vec)[t3i];
809 genTransOrderConstraint(t1rec, t2rec, t3rec);
815 void ConstGen::genTransOrderConstraint(EPRecord *t1rec, EPRecord *t2rec, EPRecord *t3rec) {
816 Constraint *c21=getOrderConstraint(t2rec, t1rec);
817 Constraint *c32=getOrderConstraint(t3rec, t2rec);
818 Constraint *c13=getOrderConstraint(t1rec, t3rec);
819 Constraint * cimpl1[]={c21, c32, c13};
820 Constraint * c1=new Constraint(OR, 3, cimpl1);
821 ADDCONSTRAINT(c1, "intertransorder");
823 Constraint *c12=getOrderConstraint(t1rec, t2rec);
824 Constraint *c23=getOrderConstraint(t2rec, t3rec);
825 Constraint *c31=getOrderConstraint(t3rec, t1rec);
826 Constraint * cimpl2[]={c12, c23, c31};
827 Constraint *c2=new Constraint(OR, 3, cimpl2);
828 ADDCONSTRAINT(c2, "intertransorder");
831 void ConstGen::addGoal(EPRecord *r, Constraint *c) {
832 rectoint->put(r, goalset->size());
833 goalset->push_back(c);
836 void ConstGen::addBranchGoal(EPRecord *r, Constraint *c) {
837 has_untaken_branches=true;
838 rectoint->put(r, goalset->size());
839 goalset->push_back(c);
842 void ConstGen::achievedGoal(EPRecord *r) {
843 if (rectoint->contains(r)) {
844 uint index=rectoint->get(r);
845 //if (goalvararray[index] != NULL)
846 //model_print("Run Clearing goal index %d\n",index);
847 goalvararray[index]=NULL;
851 void ConstGen::addConstraint(Constraint *c) {
852 ModelVector<Constraint *> *vec=c->simplify();
853 for(uint i=0;i<vec->size();i++) {
854 Constraint *simp=(*vec)[i];
855 if (simp->type==TRUE)
857 ASSERT(simp->type!=FALSE);
858 simp->printDIMACS(this);
859 #ifdef VERBOSE_CONSTRAINTS
869 void ConstGen::printNegConstraint(uint value) {
871 solver->addClauseLiteral(val);
874 void ConstGen::printConstraint(uint value) {
875 solver->addClauseLiteral(value);
878 bool * ConstGen::runSolver() {
879 int solution=solver->solve();
880 if (solution == IS_UNSAT) {
882 } else if (solution == IS_SAT) {
883 bool * assignments=(bool *)model_malloc(sizeof(bool)*(varindex+1));
884 for(uint i=0;i<=varindex;i++)
885 assignments[i]=solver->getValue(i);
890 model_print_err("INDETER\n");
891 model_print("INDETER\n");
897 Constraint * ConstGen::getOrderConstraint(EPRecord *first, EPRecord *second) {
899 if (first->getEP()->get_tid()==second->getEP()->get_tid()) {
900 if (first->getEP()->compare(second->getEP())==CR_AFTER)
907 RecPair rp(first, second);
908 RecPair *rpc=rpt->get(&rp);
911 first->getEP()->get_tid()==second->getEP()->get_tid()) {
912 if (first->getEP()->compare(second->getEP())==CR_AFTER)
921 Constraint *c=rpc->constraint;
922 if (rpc->epr1!=first) {
923 //have to flip arguments
930 bool ConstGen::getOrder(EPRecord *first, EPRecord *second, bool * satsolution) {
931 RecPair rp(first, second);
932 RecPair *rpc=rpt->get(&rp);
935 first->getEP()->get_tid()==second->getEP()->get_tid()) {
936 if (first->getEP()->compare(second->getEP())==CR_AFTER)
946 Constraint *c=rpc->constraint;
947 CType type=c->getType();
952 else if (type==FALSE)
955 uint index=c->getVar();
956 order=satsolution[index];
958 if (rpc->epr1==first)
964 /** This function determines whether events first and second are
965 * ordered by start and join operations. */
967 bool ConstGen::orderThread(EPRecord *first, EPRecord *second) {
968 ExecPoint * ep1=first->getEP();
969 ExecPoint * ep2=second->getEP();
970 thread_id_t thr1=ep1->get_tid();
971 thread_id_t thr2=ep2->get_tid();
972 Thread *tr2=execution->get_thread(thr2);
973 EPRecord *thr2start=tr2->getParentRecord();
974 if (thr2start!=NULL) {
975 ExecPoint *epthr2start=thr2start->getEP();
976 if (epthr2start->get_tid()==thr1 &&
977 ep1->compare(epthr2start)==CR_AFTER)
980 ModelVector<EPRecord *> * joinvec=execution->getJoins();
981 for(uint i=0;i<joinvec->size();i++) {
982 EPRecord *join=(*joinvec)[i];
983 ExecPoint *jp=join->getEP();
984 if (jp->get_tid()==thr2 &&
985 jp->compare(ep2)==CR_AFTER)
991 /** This function generates an ordering constraint for two events. */
993 void ConstGen::createOrderConstraint(EPRecord *first, EPRecord *second) {
994 RecPair * rp=new RecPair(first, second);
995 if (!rpt->contains(rp)) {
996 if (orderThread(first, second))
997 rp->constraint=&ctrue;
998 else if (orderThread(second, first))
999 rp->constraint=&cfalse;
1001 rp->constraint=getNewVar();
1009 Constraint * ConstGen::getNewVar() {
1011 if (varindex>vars->size()) {
1012 var=new Constraint(VAR, varindex);
1013 Constraint *varneg=new Constraint(NOTVAR, varindex);
1014 var->setNeg(varneg);
1015 varneg->setNeg(var);
1016 vars->push_back(var);
1018 var=(*vars)[varindex-1];
1024 /** Gets an array of new variables. */
1026 void ConstGen::getArrayNewVars(uint num, Constraint **carray) {
1027 for(uint i=0;i<num;i++)
1028 carray[i]=getNewVar();
1031 StoreLoadSet * ConstGen::getStoreLoadSet(EPRecord *record) {
1032 IntIterator *it=record->getSet(VC_ADDRINDEX)->iterator();
1033 void *addr=(void *)it->next();
1035 return storeloadtable->get(addr);
1038 /** Returns a constraint that is true if the output of record has the
1041 Constraint * ConstGen::getRetValueEncoding(EPRecord *record, uint64_t value) {
1042 switch(record->getType()) {
1044 return equalstable->get(record)->getValueEncoding(value);
1046 return functiontable->get(record)->getValueEncoding(value);
1048 return getStoreLoadSet(record)->getValueEncoding(this, record, value);
1051 return getStoreLoadSet(record)->getRMWRValueEncoding(this, record, value);
1059 Constraint * ConstGen::getMemValueEncoding(EPRecord *record, uint64_t value) {
1060 switch(record->getType()) {
1062 return getStoreLoadSet(record)->getValueEncoding(this, record, value);
1064 return getStoreLoadSet(record)->getValueEncoding(this, record, value);
1071 /** Return true if the execution of record implies the execution of
1074 bool ConstGen::subsumesExecutionConstraint(EPRecord *recordsubsumes, EPRecord *record) {
1075 EPValue *branch=record->getBranch();
1076 EPValue *branchsubsumes=recordsubsumes->getBranch();
1077 if (branchsubsumes != NULL) {
1078 bool branchsubsumed=false;
1079 while(branch!=NULL) {
1080 if (branchsubsumes==branch) {
1081 branchsubsumed=true;
1084 branch=branch->getRecord()->getBranch();
1086 if (!branchsubsumed)
1089 RecordSet *srs=execcondtable->get(recordsubsumes);
1092 RecordIterator *sri=srs->iterator();
1093 while(sri->hasNext()) {
1094 EPRecord *rec=sri->next();
1096 if (!getOrderConstraint(rec, record)->isTrue()) {
1106 Constraint * ConstGen::getExecutionConstraint(EPRecord *record) {
1107 EPValue *branch=record->getBranch();
1108 RecordSet *srs=execcondtable->get(record);
1109 int size=srs==NULL ? 0 : srs->getSize();
1113 Constraint *array[size];
1116 RecordIterator *sri=srs->iterator();
1117 while(sri->hasNext()) {
1118 EPRecord *rec=sri->next();
1119 EPValue *recbranch=rec->getBranch();
1120 BranchRecord *guardbr=branchtable->get(recbranch->getRecord());
1121 array[index++]=guardbr->getBranch(recbranch)->negate();
1126 BranchRecord *guardbr=branchtable->get(branch->getRecord());
1127 array[index++]=guardbr->getBranch(branch);
1134 return new Constraint(AND, index, array);
1137 bool ConstGen::isAlwaysExecuted(EPRecord *record) {
1138 EPValue *branch=record->getBranch();
1139 RecordSet *srs=execcondtable->get(record);
1140 int size=srs==NULL ? 0 : srs->getSize();
1147 void ConstGen::insertBranch(EPRecord *record) {
1148 uint numvalue=record->numValues();
1149 /** need one value for new directions */
1150 if (numvalue<record->getLen()) {
1152 if (model->params.noexecyields) {
1153 incompleteexploredbranch->add(record);
1156 /** need extra value to represent that branch wasn't executed. **/
1157 bool alwaysexecuted=isAlwaysExecuted(record);
1158 if (!alwaysexecuted)
1160 uint numbits=NUMBITS(numvalue-1);
1161 Constraint *bits[numbits];
1162 getArrayNewVars(numbits, bits);
1163 BranchRecord *br=new BranchRecord(record, numbits, bits, alwaysexecuted);
1164 branchtable->put(record, br);
1167 void ConstGen::processBranch(EPRecord *record) {
1168 BranchRecord *br=branchtable->get(record);
1169 if (record->numValues()<record->getLen()) {
1170 Constraint *goal=br->getNewBranch();
1171 ADDBRANCHGOAL(record, goal,"newbranch");
1174 /** Insert criteria of parent branch going the right way. **/
1175 Constraint *baseconstraint=getExecutionConstraint(record);
1177 if (!isAlwaysExecuted(record)) {
1178 Constraint *parentbranch=new Constraint(IMPLIES, br->getAnyBranch(), baseconstraint);
1179 ADDCONSTRAINT(parentbranch, "parentbranch");
1182 /** Insert criteria for directions */
1183 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, VC_BASEINDEX);
1184 ASSERT(depvec->size()==1);
1185 EPRecord * val_record=(*depvec)[0];
1186 for(unsigned int i=0;i<record->numValues();i++) {
1187 EPValue * branchval=record->getValue(i);
1188 uint64_t val=branchval->getValue();
1191 Constraint *execconstraint=getExecutionConstraint(record);
1192 Constraint *br_false=new Constraint(IMPLIES,
1193 new Constraint(AND, execconstraint,
1194 getRetValueEncoding(val_record, val)), br->getBranch(branchval));
1195 ADDCONSTRAINT(br_false, "br_false");
1197 if (record->getBranchAnyValue()) {
1198 if (getRetValueEncoding(val_record, 0)!=NULL) {
1199 Constraint *execconstraint=getExecutionConstraint(record);
1200 Constraint *br_true1=new Constraint(IMPLIES, new Constraint(AND, getRetValueEncoding(val_record, 0)->negate(),
1202 br->getBranch(branchval));
1203 ADDCONSTRAINT(br_true1, "br_true1");
1205 for(unsigned int j=0;j<val_record->numValues();j++) {
1206 EPValue * epval=val_record->getValue(j);
1207 Constraint *execconstraint=getExecutionConstraint(record);
1208 Constraint *valuematches=getRetValueEncoding(val_record, epval->getValue());
1209 Constraint *br_true2=new Constraint(IMPLIES, new Constraint(AND, execconstraint, valuematches), br->getBranch(branchval));
1210 ADDCONSTRAINT(br_true2, "br_true2");
1214 Constraint *execconstraint=getExecutionConstraint(record);
1215 Constraint *br_val=new Constraint(IMPLIES, new Constraint(AND, execconstraint, getRetValueEncoding(val_record, val)), br->getBranch(branchval));
1216 ADDCONSTRAINT(br_val, "br_val");
1222 void ConstGen::insertFunction(EPRecord *record) {
1223 FunctionRecord * fr=new FunctionRecord(this, record);
1224 functiontable->put(record, fr);
1227 void ConstGen::insertEquals(EPRecord *record) {
1228 EqualsRecord * fr=new EqualsRecord(this, record);
1229 equalstable->put(record, fr);
1232 void ConstGen::processLoad(EPRecord *record) {
1233 LoadRF * lrf=new LoadRF(record, this);
1234 lrf->genConstraints(this);
1236 processAddresses(record);
1239 /** This procedure generates the constraints that set the address
1240 variables for load/store/rmw operations. */
1242 void ConstGen::processAddresses(EPRecord *record) {
1243 StoreLoadSet *sls=getStoreLoadSet(record);
1244 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, VC_ADDRINDEX);
1246 //we have a hard coded address
1247 const void *addr=record->getValue(0)->getAddr();
1248 Constraint *addrenc=sls->getAddressEncoding(this, record, addr);
1249 ADDCONSTRAINT(addrenc,"fixedaddress");
1251 //we take as input an address and have to generate implications
1252 //for each possible input address
1253 ASSERT(depvec->size()==1);
1254 EPRecord *src=(*depvec)[0];
1255 IntIterator *it=record->getSet(VC_ADDRINDEX)->iterator();
1257 uintptr_t offset=record->getOffset();
1259 while(it->hasNext()) {
1260 uint64_t addr=it->next();
1261 Constraint *srcenc=getRetValueEncoding(src, addr-offset);
1262 Constraint *addrenc=sls->getAddressEncoding(this, record, (void *) addr);
1263 Constraint *addrmatch=new Constraint(IMPLIES, srcenc, addrenc);
1264 ADDCONSTRAINT(addrmatch,"setaddress");
1270 void ConstGen::processCAS(EPRecord *record) {
1272 LoadRF * lrf=new LoadRF(record, this);
1273 lrf->genConstraints(this);
1275 //Next see if we are successful
1276 Constraint *eq=getNewVar();
1277 ModelVector<EPRecord *> * depveccas=execution->getRevDependences(record, VC_OLDVALCASINDEX);
1278 if (depveccas==NULL) {
1279 //Hard coded old value
1280 IntIterator *iit=record->getSet(VC_OLDVALCASINDEX)->iterator();
1281 uint64_t valcas=iit->next();
1283 Constraint *rmwr=getStoreLoadSet(record)->getRMWRValueEncoding(this, record, valcas);
1285 Constraint *cascond=eq->negate();
1286 ADDCONSTRAINT(cascond, "cascond");
1288 Constraint *cascond=generateEquivConstraint(eq, rmwr);
1289 ADDCONSTRAINT(cascond, "cascond");
1292 ASSERT(depveccas->size()==1);
1293 EPRecord *src=(*depveccas)[0];
1294 IntIterator *it=getStoreLoadSet(record)->getValues()->iterator();
1296 while(it->hasNext()) {
1297 uint64_t valcas=it->next();
1298 Constraint *srcenc=getRetValueEncoding(src, valcas);
1299 Constraint *storeenc=getStoreLoadSet(record)->getRMWRValueEncoding(this, record, valcas);
1301 if (srcenc!=NULL && storeenc!=NULL) {
1302 Constraint *cond=new Constraint(AND,
1303 new Constraint(IMPLIES, srcenc->clone(), eq),
1304 new Constraint(IMPLIES, eq, srcenc));
1305 Constraint *cas=new Constraint(IMPLIES, storeenc, cond);
1306 ADDCONSTRAINT(cas, "cas");
1307 } else if (srcenc==NULL) {
1308 Constraint *casfail=new Constraint(IMPLIES, storeenc, eq->negate());
1309 ADDCONSTRAINT(casfail,"casfail_eq");
1311 //srcenc must be non-null and store-encoding must be null
1316 IntIterator *iit=record->getSet(VC_OLDVALCASINDEX)->iterator();
1317 while(iit->hasNext()) {
1318 uint64_t val=iit->next();
1319 if (!getStoreLoadSet(record)->getValues()->contains(val)) {
1320 Constraint *srcenc=getRetValueEncoding(src, val);
1321 Constraint *casfail=new Constraint(IMPLIES, srcenc, eq->negate());
1322 ADDCONSTRAINT(casfail,"casfailretval");
1328 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, VC_BASEINDEX);
1330 IntIterator *iit=record->getSet(VC_BASEINDEX)->iterator();
1331 uint64_t val=iit->next();
1333 Constraint *storeenc=getMemValueEncoding(record, val);
1334 Constraint *casmemsuc=new Constraint(IMPLIES, eq, storeenc);
1335 ADDCONSTRAINT(casmemsuc, "casmemsuc");
1337 ASSERT(depvec->size()==1);
1338 EPRecord *src=(*depvec)[0];
1339 IntIterator *it=record->getStoreSet()->iterator();
1341 while(it->hasNext()) {
1342 uint64_t val=it->next();
1343 Constraint *srcenc=getRetValueEncoding(src, val);
1345 //this can happen for values that are in the store set because
1346 //we re-stored them on a failed CAS
1349 Constraint *storeenc=getMemValueEncoding(record, val);
1350 Constraint *storevalue=new Constraint(IMPLIES, new Constraint(AND, eq, srcenc), storeenc);
1351 ADDCONSTRAINT(storevalue,"casmemsuc");
1355 StoreLoadSet *sls=getStoreLoadSet(record);
1357 Constraint *repeatval=generateEquivConstraint(sls->getNumValVars(), sls->getValVars(this, record), sls->getRMWRValVars(this, record));
1358 Constraint *failcas=new Constraint(IMPLIES, eq->negate(), repeatval);
1359 ADDCONSTRAINT(failcas,"casmemfail");
1361 processAddresses(record);
1364 void ConstGen::processEXC(EPRecord *record) {
1366 LoadRF * lrf=new LoadRF(record, this);
1367 lrf->genConstraints(this);
1370 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, VC_BASEINDEX);
1372 IntIterator *iit=record->getSet(VC_BASEINDEX)->iterator();
1373 uint64_t val=iit->next();
1375 Constraint *storeenc=getMemValueEncoding(record, val);
1376 ADDCONSTRAINT(storeenc, "excmemsuc");
1378 ASSERT(depvec->size()==1);
1379 EPRecord *src=(*depvec)[0];
1380 IntIterator *it=record->getStoreSet()->iterator();
1382 while(it->hasNext()) {
1383 uint64_t val=it->next();
1384 Constraint *srcenc=getRetValueEncoding(src, val);
1385 Constraint *storeenc=getMemValueEncoding(record, val);
1386 Constraint *storevalue=new Constraint(IMPLIES, srcenc, storeenc);
1387 ADDCONSTRAINT(storevalue,"excmemsuc");
1392 processAddresses(record);
1395 void ConstGen::processAdd(EPRecord *record) {
1397 LoadRF * lrf=new LoadRF(record, this);
1398 lrf->genConstraints(this);
1400 Constraint *var=getNewVar();
1401 Constraint *newadd=new Constraint(AND, var, getExecutionConstraint(record));
1402 ADDGOAL(record, newadd, "newadd");
1404 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, VC_BASEINDEX);
1406 IntIterator *valit=record->getSet(VC_BASEINDEX)->iterator();
1407 uint64_t val=valit->next();
1409 IntHashSet *valset=getStoreLoadSet(record)->getValues();
1410 IntIterator *sis=valset->iterator();
1411 while(sis->hasNext()) {
1412 uint64_t memval=sis->next();
1413 uint64_t sumval=(memval+val)&getmask(record->getLen());
1415 if (valset->contains(sumval)) {
1417 Constraint *loadenc=getStoreLoadSet(record)->getRMWRValueEncoding(this, record, memval);
1418 Constraint *storeenc=getMemValueEncoding(record, sumval);
1419 Constraint *notvar=var->negate();
1420 Constraint *addinputfix=new Constraint(IMPLIES, loadenc, new Constraint(AND, storeenc, notvar));
1421 ADDCONSTRAINT(addinputfix, "addinputfix");
1427 ASSERT(depvec->size()==1);
1428 EPRecord *src=(*depvec)[0];
1429 IntIterator *it=record->getStoreSet()->iterator();
1430 IntHashSet *valset=getStoreLoadSet(record)->getValues();
1432 while(it->hasNext()) {
1433 uint64_t val=it->next();
1434 IntIterator *sis=valset->iterator();
1435 while(sis->hasNext()) {
1436 uint64_t memval=sis->next();
1437 uint64_t sum=(memval+val)&getmask(record->getLen());
1438 if (valset->contains(sum)) {
1439 Constraint *srcenc=getRetValueEncoding(src, val);
1440 Constraint *loadenc=getStoreLoadSet(record)->getRMWRValueEncoding(this, record, memval);
1441 Constraint *storeenc=getMemValueEncoding(record, sum);
1442 Constraint *notvar=var->negate();
1443 Constraint *addop=new Constraint(IMPLIES, new Constraint(AND, srcenc, loadenc),
1444 new Constraint(AND, notvar, storeenc));
1445 ADDCONSTRAINT(addop,"addinputvar");
1453 processAddresses(record);
1456 /** This function ensures that the value of a store's SAT variables
1457 matches the store's input value.
1459 TODO: Could optimize the case where the encodings are the same...
1462 void ConstGen::processStore(EPRecord *record) {
1463 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, VC_BASEINDEX);
1465 //We have a hard coded value
1466 uint64_t val=record->getValue(0)->getValue();
1467 Constraint *storeenc=getMemValueEncoding(record, val);
1468 ADDCONSTRAINT(storeenc,"storefix");
1470 //We have a value from an input
1471 ASSERT(depvec->size()==1);
1472 EPRecord *src=(*depvec)[0];
1473 IntIterator *it=record->getStoreSet()->iterator();
1475 while(it->hasNext()) {
1476 uint64_t val=it->next();
1477 Constraint *srcenc=getRetValueEncoding(src, val);
1478 Constraint *storeenc=getMemValueEncoding(record, val);
1479 Constraint *storevalue=new Constraint(IMPLIES, srcenc, storeenc);
1480 ADDCONSTRAINT(storevalue,"storevar");
1484 processAddresses(record);
1489 void ConstGen::computeYieldCond(EPRecord *record) {
1490 ExecPoint *yieldep=record->getEP();
1491 EPRecord *prevyield=NULL;
1492 ExecPoint *prevyieldep=NULL;
1494 for(int i=(int)(yieldlist->size()-1);i>=0;i--) {
1495 EPRecord *tmpyield=(*yieldlist)[i];
1496 ExecPoint *tmpep=tmpyield->getEP();
1497 //Do we have a previous yield operation from the same thread
1498 if (tmpep->get_tid()==yieldep->get_tid() &&
1499 yieldep->compare(tmpep)==CR_BEFORE) {
1502 prevyieldep=prevyield->getEP();
1507 yieldlist->push_back(record);
1509 ModelVector<Constraint *> * novel_branches=new ModelVector<Constraint *>();
1510 RecordIterator *sri=incompleteexploredbranch->iterator();
1511 while(sri->hasNext()) {
1512 EPRecord * unexploredbranch=sri->next();
1513 ExecPoint * branchep=unexploredbranch->getEP();
1514 if (branchep->get_tid()!=yieldep->get_tid()) {
1519 if (yieldep->compare(branchep)!=CR_BEFORE) {
1520 //Branch does not occur before yield, so skip
1524 //See if the previous yield already accounts for this branch
1525 if (prevyield != NULL &&
1526 prevyieldep->compare(branchep)==CR_BEFORE) {
1527 //Branch occurs before previous yield, so we can safely skip this branch
1530 //This is a branch that could prevent this yield from being executed
1531 BranchRecord *br=branchtable->get(unexploredbranch);
1532 Constraint * novel_branch=br->getNewBranch();
1533 novel_branches->push_back(novel_branch);
1536 int num_constraints=((prevyield==NULL)?0:1)+novel_branches->size();
1537 Constraint *carray[num_constraints];
1540 if (prevyield!=NULL) {
1541 carray[arr_index++]=yieldtable->get(prevyield);//get constraint for old yield
1543 for(uint i=0;i<novel_branches->size();i++) {
1544 carray[arr_index++]=(*novel_branches)[i];
1547 Constraint *cor=num_constraints!=0?new Constraint(OR, num_constraints, carray):&cfalse;
1549 Constraint *var=getNewVar();
1550 //If the variable is true, then we need to have taken some branch
1551 //ahead of the yield
1552 Constraint *implies=new Constraint(IMPLIES, var, cor);
1553 ADDCONSTRAINT(implies, "possiblebranchnoyield");
1554 yieldtable->put(record, var);
1556 delete novel_branches;
1561 /** Handle yields by just forbidding them via the SAT formula. */
1563 void ConstGen::processYield(EPRecord *record) {
1564 if (model->params.noexecyields) {
1565 computeYieldCond(record);
1566 Constraint * noexecyield=getExecutionConstraint(record)->negate();
1567 Constraint * branchaway=yieldtable->get(record);
1568 Constraint * avoidbranch=new Constraint(OR, noexecyield, branchaway);
1569 ADDCONSTRAINT(avoidbranch, "noexecyield");
1573 void ConstGen::processLoopPhi(EPRecord *record) {
1574 EPRecordIDSet *phiset=record->getPhiLoopTable();
1575 EPRecordIDIterator *rit=phiset->iterator();
1577 while(rit->hasNext()) {
1578 struct RecordIDPair *rip=rit->next();
1579 EPRecord *input=rip->idrecord;
1581 IntIterator * it=record->getSet(VC_BASEINDEX)->iterator();
1582 while(it->hasNext()) {
1583 uint64_t value=it->next();
1584 Constraint * inputencoding=getRetValueEncoding(input, value);
1585 if (inputencoding==NULL)
1587 Constraint * branchconstraint=getExecutionConstraint(rip->record);
1588 Constraint * outputencoding=getRetValueEncoding(record, value);
1589 Constraint * phiimplication=new Constraint(IMPLIES, new Constraint(AND, inputencoding, branchconstraint), outputencoding);
1590 ADDCONSTRAINT(phiimplication,"philoop");
1597 void ConstGen::processPhi(EPRecord *record) {
1598 ModelVector<EPRecord *> * inputs=execution->getRevDependences(record, VC_BASEINDEX);
1599 for(uint i=0;i<inputs->size();i++) {
1600 EPRecord * input=(*inputs)[i];
1602 IntIterator * it=record->getSet(VC_BASEINDEX)->iterator();
1603 while(it->hasNext()) {
1604 uint64_t value=it->next();
1605 Constraint * inputencoding=getRetValueEncoding(input, value);
1606 if (inputencoding==NULL)
1608 Constraint * branchconstraint=getExecutionConstraint(input);
1609 Constraint * outputencoding=getRetValueEncoding(record, value);
1610 Constraint * phiimplication=new Constraint(IMPLIES, new Constraint(AND, inputencoding, branchconstraint), outputencoding);
1611 ADDCONSTRAINT(phiimplication,"phi");
1617 void ConstGen::processFunction(EPRecord *record) {
1618 if (record->getLoopPhi()) {
1619 processLoopPhi(record);
1621 } else if (record->getPhi()) {
1626 CGoalSet *knownbehaviors=record->completedGoalSet();
1627 CGoalIterator *cit=knownbehaviors->iterator();
1628 uint numinputs=record->getNumFuncInputs();
1629 EPRecord * inputs[numinputs];
1630 for(uint i=0;i<numinputs;i++) {
1631 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, i+VC_BASEINDEX);
1632 ASSERT(depvec->size()==1);
1633 inputs[i]=(*depvec)[0];
1635 while(cit->hasNext()) {
1636 CGoal *goal=cit->next();
1637 Constraint *carray[numinputs];
1638 if (record->isSharedGoals()) {
1639 bool badvalue=false;
1640 for(uint i=0;i<numinputs;i++) {
1641 uint64_t inputval=goal->getValue(i+VC_BASEINDEX);
1642 if (!record->getSet(i+VC_BASEINDEX)->contains(inputval)) {
1651 /* Build up constraints for each input */
1652 for(uint i=0;i<numinputs;i++) {
1653 uint64_t inputval=goal->getValue(i+VC_BASEINDEX);
1654 Constraint * inputc=getRetValueEncoding(inputs[i], inputval);
1655 ASSERT(inputc!=NULL);
1658 Constraint * outputconstraint=getRetValueEncoding(record, goal->getOutput());
1660 ADDCONSTRAINT(outputconstraint,"functionimpl");
1662 Constraint * functionimplication=new Constraint(IMPLIES, new Constraint(AND, numinputs, carray), outputconstraint);
1663 ADDCONSTRAINT(functionimplication,"functionimpl");
1668 FunctionRecord *fr=functiontable->get(record);
1669 Constraint *goal=fr->getNoValueEncoding();
1670 Constraint *newfunc=new Constraint(AND, goal, getExecutionConstraint(record));
1671 ADDGOAL(record, newfunc, "newfunc");
1674 void ConstGen::processEquals(EPRecord *record) {
1675 ASSERT (record->getNumFuncInputs() == 2);
1676 EPRecord * inputs[2];
1678 for(uint i=0;i<2;i++) {
1679 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, i+VC_BASEINDEX);
1682 } else if (depvec->size()==1) {
1683 inputs[i]=(*depvec)[0];
1684 } else ASSERT(false);
1687 //rely on this being a variable
1688 Constraint * outputtrue=getRetValueEncoding(record, 1);
1689 ASSERT(outputtrue->getType()==VAR);
1691 if (inputs[0]!=NULL && inputs[1]!=NULL &&
1692 (inputs[0]->getType()==LOAD || inputs[0]->getType()==RMW) &&
1693 (inputs[1]->getType()==LOAD || inputs[1]->getType()==RMW) &&
1694 (getStoreLoadSet(inputs[0])==getStoreLoadSet(inputs[1]))) {
1695 StoreLoadSet * sls=getStoreLoadSet(inputs[0]);
1696 int numvalvars=sls->getNumValVars();
1697 Constraint **valvar1=(inputs[0]->getType()==RMW) ? sls->getRMWRValVars(this, inputs[0]) : sls->getValVars(this, inputs[0]);
1698 Constraint **valvar2=(inputs[1]->getType()==RMW) ? sls->getRMWRValVars(this, inputs[1]) : sls->getValVars(this, inputs[1]);
1701 Constraint *vars[numvalvars];
1702 for(int i=0;i<numvalvars;i++) {
1703 vars[i]=getNewVar();
1704 Constraint *var1=valvar1[i];
1705 Constraint *var2=valvar2[i];
1706 Constraint * array[]={var1, var2->negate(), vars[i]->negate()};
1707 Constraint * array2[]={var2, var1->negate(), vars[i]->negate()};
1708 Constraint * a=new Constraint(OR, 3, array);
1709 ADDCONSTRAINT(a, "equala");
1710 Constraint * a2=new Constraint(OR, 3, array2);
1711 ADDCONSTRAINT(a2, "equala2");
1712 Constraint * arrayb[]={var1, var2, vars[i]};
1713 Constraint * array2b[]={var2->negate(), var1->negate(), vars[i]};
1714 Constraint * b=new Constraint(OR, 3, arrayb);
1715 ADDCONSTRAINT(b, "equalb");
1716 Constraint *b2=new Constraint(OR, 3, array2b);
1717 ADDCONSTRAINT(b2, "equalb2");
1719 ADDCONSTRAINT(new Constraint(IMPLIES, new Constraint(AND, numvalvars, vars), outputtrue),"impequal1");
1721 ADDCONSTRAINT(new Constraint(IMPLIES, outputtrue, new Constraint(AND, numvalvars, vars)), "impequal2");
1725 Constraint * functionimplication=new Constraint(IMPLIES,generateEquivConstraint(numvalvars, valvar1, valvar2), outputtrue);
1726 ADDCONSTRAINT(functionimplication,"equalsimplspecial");
1727 Constraint * functionimplicationneg=new Constraint(IMPLIES,outputtrue, generateEquivConstraint(numvalvars, valvar1, valvar2));
1728 ADDCONSTRAINT(functionimplicationneg,"equalsimplspecialneg");
1733 if (inputs[0]==NULL && inputs[1]==NULL) {
1734 IntIterator *iit0=record->getSet(VC_BASEINDEX+0)->iterator();
1735 uint64_t constval=iit0->next();
1737 IntIterator *iit1=record->getSet(VC_BASEINDEX+1)->iterator();
1738 uint64_t constval2=iit1->next();
1741 if (constval==constval2) {
1742 ADDCONSTRAINT(outputtrue, "equalsconst");
1744 ADDCONSTRAINT(outputtrue->negate(), "equalsconst");
1749 if (inputs[0]==NULL ||
1751 int nullindex=inputs[0]==NULL ? 0 : 1;
1752 IntIterator *iit=record->getSet(VC_BASEINDEX+nullindex)->iterator();
1753 uint64_t constval=iit->next();
1756 record->getSet(VC_BASEINDEX+nullindex);
1757 EPRecord *r=inputs[1-nullindex];
1758 Constraint *l=getRetValueEncoding(r, constval);
1759 Constraint *functionimplication=new Constraint(IMPLIES, l, outputtrue);
1760 ADDCONSTRAINT(functionimplication,"equalsimpl");
1762 Constraint *l2=getRetValueEncoding(r, constval);
1763 Constraint *functionimplication2=new Constraint(IMPLIES, outputtrue, l2);
1764 ADDCONSTRAINT(functionimplication2,"equalsimpl");
1767 IntIterator *iit=record->getSet(VC_BASEINDEX)->iterator();
1768 while(iit->hasNext()) {
1769 uint64_t val1=iit->next();
1771 IntIterator *iit2=record->getSet(VC_BASEINDEX+1)->iterator();
1772 while(iit2->hasNext()) {
1773 uint64_t val2=iit2->next();
1774 Constraint *l=getRetValueEncoding(inputs[0], val1);
1775 Constraint *r=getRetValueEncoding(inputs[1], val2);
1776 Constraint *imp=(val1==val2) ? outputtrue : outputtrue->negate();
1777 Constraint * functionimplication=new Constraint(IMPLIES, new Constraint(AND, l, r), imp);
1778 ADDCONSTRAINT(functionimplication,"equalsimpl");
1786 void ConstGen::processFence(EPRecord *record) {
1787 //do we already account for the fence?
1788 if (isAlwaysExecuted(record))
1790 ExecPoint * record_ep=record->getEP();
1791 thread_id_t tid=record_ep->get_tid();
1792 uint thread=id_to_int(tid);
1793 ModelVector<EPRecord *> *tvec=(*threadactions)[thread];
1794 uint size=tvec->size();
1796 EPRecord *prevstore=NULL;
1798 for(i=0;i<size;i++) {
1799 EPRecord *rec=(*tvec)[i];
1800 if (rec->getType()==STORE) {
1803 if (rec == record) {
1808 if (prevstore == NULL) {
1812 EPRecord *rec=(*tvec)[i];
1813 if (rec->getType()==LOAD) {
1814 Constraint * condition=getExecutionConstraint(record);
1815 Constraint * storeload=getOrderConstraint(prevstore, rec);
1816 Constraint * c=new Constraint(IMPLIES, condition, storeload);
1817 ADDCONSTRAINT(c, "fence");
1824 /** processRecord performs actions on second traversal of event
1827 void ConstGen::processRecord(EPRecord *record) {
1828 switch (record->getType()) {
1830 processFunction(record);
1833 processEquals(record);
1836 processLoad(record);
1839 processStore(record);
1843 processFence(record);
1848 processFence(record);
1850 if (record->getOp()==ADD) {
1852 } else if (record->getOp()==CAS) {
1854 } else if (record->getOp()==EXC) {
1860 processYield(record);
1863 processBranch(record);
1870 /** visitRecord performs actions done on first traversal of event
1873 void ConstGen::visitRecord(EPRecord *record) {
1874 switch (record->getType()) {
1876 recordExecCond(record);
1877 insertEquals(record);
1880 recordExecCond(record);
1881 insertFunction(record);
1885 recordExecCond(record);
1886 insertAction(record);
1890 recordExecCond(record);
1891 insertAction(record);
1892 groupMemoryOperations(record);
1895 recordExecCond(record);
1896 insertAction(record);
1897 groupMemoryOperations(record);
1900 recordExecCond(record);
1901 insertAction(record);
1902 groupMemoryOperations(record);
1905 recordExecCond(record);
1906 insertBranch(record);
1909 recordExecCond(record);
1912 recordExecCond(record);
1913 insertNonLocal(record);
1916 insertLabel(record);
1919 recordExecCond(record);
1926 void ConstGen::recordExecCond(EPRecord *record) {
1927 ExecPoint *eprecord=record->getEP();
1928 EPValue * branchval=record->getBranch();
1929 EPRecord * branch=(branchval==NULL) ? NULL : branchval->getRecord();
1930 ExecPoint *epbranch= (branch==NULL) ? NULL : branch->getEP();
1931 RecordSet *srs=NULL;
1932 RecordIterator *sri=nonlocaltrans->iterator();
1933 while(sri->hasNext()) {
1934 EPRecord *nonlocal=sri->next();
1935 ExecPoint *epnl=nonlocal->getEP();
1936 if (epbranch!=NULL) {
1937 if (epbranch->compare(epnl)==CR_BEFORE) {
1938 //branch occurs after non local and thus will subsume condition
1939 //branch subsumes this condition
1943 if (eprecord->compare(epnl)==CR_BEFORE) {
1944 //record occurs after non-local, so add it to set
1946 srs=new RecordSet();
1952 execcondtable->put(record, srs);
1955 void ConstGen::insertNonLocal(EPRecord *record) {
1956 nonlocaltrans->add(record);
1959 void ConstGen::insertLabel(EPRecord *record) {
1960 RecordIterator *sri=nonlocaltrans->iterator();
1961 while(sri->hasNext()) {
1962 EPRecord *nonlocal=sri->next();
1963 if (nonlocal->getNextRecord()==record)
1970 void ConstGen::traverseRecord(EPRecord *record, bool initial) {
1973 visitRecord(record);
1975 processRecord(record);
1977 if (record->getType()==LOOPENTER) {
1978 workstack->push_back(record->getNextRecord());
1979 workstack->push_back(record->getChildRecord());
1982 if (record->getChildRecord()!=NULL) {
1983 workstack->push_back(record->getChildRecord());
1985 if (record->getType()==NONLOCALTRANS) {
1988 if (record->getType()==YIELD && model->params.noexecyields) {
1991 if (record->getType()==LOOPEXIT) {
1994 if (record->getType()==BRANCHDIR) {
1995 EPRecord *next=record->getNextRecord();
1997 workstack->push_back(next);
1998 for(uint i=0;i<record->numValues();i++) {
1999 EPValue *branchdir=record->getValue(i);
2001 //Could have an empty branch, so make sure the branch actually
2003 if (branchdir->getFirstRecord()!=NULL)
2004 workstack->push_back(branchdir->getFirstRecord());
2008 record=record->getNextRecord();
2009 } while(record!=NULL);
2012 unsigned int RecPairHash(RecPair *rp) {
2013 uintptr_t v=(uintptr_t) rp->epr1;
2014 uintptr_t v2=(uintptr_t) rp->epr2;
2017 return (uint)((x>>4)^(a));
2020 bool RecPairEquals(RecPair *r1, RecPair *r2) {
2021 return ((r1->epr1==r2->epr1)&&(r1->epr2==r2->epr2)) ||
2022 ((r1->epr1==r2->epr2)&&(r1->epr2==r2->epr1));