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
1498 if (yieldep->compare(tmpep)==CR_BEFORE) {
1501 prevyieldep=prevyield->getEP();
1506 yieldlist->push_back(record);
1508 ModelVector<Constraint *> * novel_branches=new ModelVector<Constraint *>();
1509 RecordIterator *sri=incompleteexploredbranch->iterator();
1510 while(sri->hasNext()) {
1511 EPRecord * unexploredbranch=sri->next();
1512 ExecPoint * branchep=unexploredbranch->getEP();
1513 if (yieldep->compare(branchep)!=CR_BEFORE) {
1514 //Branch does not occur before yield, so skip
1518 //See if the previous yield already accounts for this branch
1519 if (prevyield != NULL &&
1520 prevyieldep->compare(branchep)==CR_BEFORE) {
1521 //Branch occurs before previous yield, so we can safely skip this branch
1525 //This is a branch that could prevent this yield from being executed
1526 BranchRecord *br=branchtable->get(unexploredbranch);
1527 Constraint * novel_branch=br->getNewBranch();
1528 novel_branches->push_back(novel_branch);
1531 int num_constraints=((prevyield==NULL)?0:1)+novel_branches->size();
1532 Constraint *carray[num_constraints];
1535 if (prevyield!=NULL) {
1536 carray[arr_index++]=yieldtable->get(prevyield);//get constraint for old yield
1538 for(uint i=0;i<novel_branches->size();i++) {
1539 carray[arr_index++]=(*novel_branches)[i];
1542 Constraint *cor=num_constraints!=0?new Constraint(OR, num_constraints, carray):&cfalse;
1544 Constraint *var=getNewVar();
1545 //If the variable is true, then we need to have taken some branch
1546 //ahead of the yield
1547 Constraint *implies=new Constraint(IMPLIES, var, cor);
1548 ADDCONSTRAINT(implies, "possiblebranchnoyield");
1549 yieldtable->put(record, var);
1551 delete novel_branches;
1556 /** Handle yields by just forbidding them via the SAT formula. */
1558 void ConstGen::processYield(EPRecord *record) {
1559 if (model->params.noexecyields) {
1560 computeYieldCond(record);
1561 Constraint * noexecyield=getExecutionConstraint(record)->negate();
1562 Constraint * branchaway=yieldtable->get(record);
1563 Constraint * avoidbranch=new Constraint(OR, noexecyield, branchaway);
1564 ADDCONSTRAINT(avoidbranch, "noexecyield");
1568 void ConstGen::processLoopPhi(EPRecord *record) {
1569 EPRecordIDSet *phiset=record->getPhiLoopTable();
1570 EPRecordIDIterator *rit=phiset->iterator();
1572 while(rit->hasNext()) {
1573 struct RecordIDPair *rip=rit->next();
1574 EPRecord *input=rip->idrecord;
1576 IntIterator * it=record->getSet(VC_BASEINDEX)->iterator();
1577 while(it->hasNext()) {
1578 uint64_t value=it->next();
1579 Constraint * inputencoding=getRetValueEncoding(input, value);
1580 if (inputencoding==NULL)
1582 Constraint * branchconstraint=getExecutionConstraint(rip->record);
1583 Constraint * outputencoding=getRetValueEncoding(record, value);
1584 Constraint * phiimplication=new Constraint(IMPLIES, new Constraint(AND, inputencoding, branchconstraint), outputencoding);
1585 ADDCONSTRAINT(phiimplication,"philoop");
1592 void ConstGen::processPhi(EPRecord *record) {
1593 ModelVector<EPRecord *> * inputs=execution->getRevDependences(record, VC_BASEINDEX);
1594 for(uint i=0;i<inputs->size();i++) {
1595 EPRecord * input=(*inputs)[i];
1597 IntIterator * it=record->getSet(VC_BASEINDEX)->iterator();
1598 while(it->hasNext()) {
1599 uint64_t value=it->next();
1600 Constraint * inputencoding=getRetValueEncoding(input, value);
1601 if (inputencoding==NULL)
1603 Constraint * branchconstraint=getExecutionConstraint(input);
1604 Constraint * outputencoding=getRetValueEncoding(record, value);
1605 Constraint * phiimplication=new Constraint(IMPLIES, new Constraint(AND, inputencoding, branchconstraint), outputencoding);
1606 ADDCONSTRAINT(phiimplication,"phi");
1612 void ConstGen::processFunction(EPRecord *record) {
1613 if (record->getLoopPhi()) {
1614 processLoopPhi(record);
1616 } else if (record->getPhi()) {
1621 CGoalSet *knownbehaviors=record->completedGoalSet();
1622 CGoalIterator *cit=knownbehaviors->iterator();
1623 uint numinputs=record->getNumFuncInputs();
1624 EPRecord * inputs[numinputs];
1625 for(uint i=0;i<numinputs;i++) {
1626 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, i+VC_BASEINDEX);
1627 ASSERT(depvec->size()==1);
1628 inputs[i]=(*depvec)[0];
1630 while(cit->hasNext()) {
1631 CGoal *goal=cit->next();
1632 Constraint *carray[numinputs];
1633 if (record->isSharedGoals()) {
1634 bool badvalue=false;
1635 for(uint i=0;i<numinputs;i++) {
1636 uint64_t inputval=goal->getValue(i+VC_BASEINDEX);
1637 if (!record->getSet(i+VC_BASEINDEX)->contains(inputval)) {
1646 /* Build up constraints for each input */
1647 for(uint i=0;i<numinputs;i++) {
1648 uint64_t inputval=goal->getValue(i+VC_BASEINDEX);
1649 Constraint * inputc=getRetValueEncoding(inputs[i], inputval);
1650 ASSERT(inputc!=NULL);
1653 Constraint * outputconstraint=getRetValueEncoding(record, goal->getOutput());
1655 ADDCONSTRAINT(outputconstraint,"functionimpl");
1657 Constraint * functionimplication=new Constraint(IMPLIES, new Constraint(AND, numinputs, carray), outputconstraint);
1658 ADDCONSTRAINT(functionimplication,"functionimpl");
1663 FunctionRecord *fr=functiontable->get(record);
1664 Constraint *goal=fr->getNoValueEncoding();
1665 Constraint *newfunc=new Constraint(AND, goal, getExecutionConstraint(record));
1666 ADDGOAL(record, newfunc, "newfunc");
1669 void ConstGen::processEquals(EPRecord *record) {
1670 ASSERT (record->getNumFuncInputs() == 2);
1671 EPRecord * inputs[2];
1673 for(uint i=0;i<2;i++) {
1674 ModelVector<EPRecord *> * depvec=execution->getRevDependences(record, i+VC_BASEINDEX);
1677 } else if (depvec->size()==1) {
1678 inputs[i]=(*depvec)[0];
1679 } else ASSERT(false);
1682 //rely on this being a variable
1683 Constraint * outputtrue=getRetValueEncoding(record, 1);
1684 ASSERT(outputtrue->getType()==VAR);
1686 if (inputs[0]!=NULL && inputs[1]!=NULL &&
1687 (inputs[0]->getType()==LOAD || inputs[0]->getType()==RMW) &&
1688 (inputs[1]->getType()==LOAD || inputs[1]->getType()==RMW) &&
1689 (getStoreLoadSet(inputs[0])==getStoreLoadSet(inputs[1]))) {
1690 StoreLoadSet * sls=getStoreLoadSet(inputs[0]);
1691 int numvalvars=sls->getNumValVars();
1692 Constraint **valvar1=(inputs[0]->getType()==RMW) ? sls->getRMWRValVars(this, inputs[0]) : sls->getValVars(this, inputs[0]);
1693 Constraint **valvar2=(inputs[1]->getType()==RMW) ? sls->getRMWRValVars(this, inputs[1]) : sls->getValVars(this, inputs[1]);
1696 Constraint *vars[numvalvars];
1697 for(int i=0;i<numvalvars;i++) {
1698 vars[i]=getNewVar();
1699 Constraint *var1=valvar1[i];
1700 Constraint *var2=valvar2[i];
1701 Constraint * array[]={var1, var2->negate(), vars[i]->negate()};
1702 Constraint * array2[]={var2, var1->negate(), vars[i]->negate()};
1703 Constraint * a=new Constraint(OR, 3, array);
1704 ADDCONSTRAINT(a, "equala");
1705 Constraint * a2=new Constraint(OR, 3, array2);
1706 ADDCONSTRAINT(a2, "equala2");
1707 Constraint * arrayb[]={var1, var2, vars[i]};
1708 Constraint * array2b[]={var2->negate(), var1->negate(), vars[i]};
1709 Constraint * b=new Constraint(OR, 3, arrayb);
1710 ADDCONSTRAINT(b, "equalb");
1711 Constraint *b2=new Constraint(OR, 3, array2b);
1712 ADDCONSTRAINT(b2, "equalb2");
1714 ADDCONSTRAINT(new Constraint(IMPLIES, new Constraint(AND, numvalvars, vars), outputtrue),"impequal1");
1716 ADDCONSTRAINT(new Constraint(IMPLIES, outputtrue, new Constraint(AND, numvalvars, vars)), "impequal2");
1720 Constraint * functionimplication=new Constraint(IMPLIES,generateEquivConstraint(numvalvars, valvar1, valvar2), outputtrue);
1721 ADDCONSTRAINT(functionimplication,"equalsimplspecial");
1722 Constraint * functionimplicationneg=new Constraint(IMPLIES,outputtrue, generateEquivConstraint(numvalvars, valvar1, valvar2));
1723 ADDCONSTRAINT(functionimplicationneg,"equalsimplspecialneg");
1728 if (inputs[0]==NULL && inputs[1]==NULL) {
1729 IntIterator *iit0=record->getSet(VC_BASEINDEX+0)->iterator();
1730 uint64_t constval=iit0->next();
1732 IntIterator *iit1=record->getSet(VC_BASEINDEX+1)->iterator();
1733 uint64_t constval2=iit1->next();
1736 if (constval==constval2) {
1737 ADDCONSTRAINT(outputtrue, "equalsconst");
1739 ADDCONSTRAINT(outputtrue->negate(), "equalsconst");
1744 if (inputs[0]==NULL ||
1746 int nullindex=inputs[0]==NULL ? 0 : 1;
1747 IntIterator *iit=record->getSet(VC_BASEINDEX+nullindex)->iterator();
1748 uint64_t constval=iit->next();
1751 record->getSet(VC_BASEINDEX+nullindex);
1752 EPRecord *r=inputs[1-nullindex];
1753 Constraint *l=getRetValueEncoding(r, constval);
1754 Constraint *functionimplication=new Constraint(IMPLIES, l, outputtrue);
1755 ADDCONSTRAINT(functionimplication,"equalsimpl");
1757 Constraint *l2=getRetValueEncoding(r, constval);
1758 Constraint *functionimplication2=new Constraint(IMPLIES, outputtrue, l2);
1759 ADDCONSTRAINT(functionimplication2,"equalsimpl");
1762 IntIterator *iit=record->getSet(VC_BASEINDEX)->iterator();
1763 while(iit->hasNext()) {
1764 uint64_t val1=iit->next();
1766 IntIterator *iit2=record->getSet(VC_BASEINDEX+1)->iterator();
1767 while(iit2->hasNext()) {
1768 uint64_t val2=iit2->next();
1769 Constraint *l=getRetValueEncoding(inputs[0], val1);
1770 Constraint *r=getRetValueEncoding(inputs[1], val2);
1771 Constraint *imp=(val1==val2) ? outputtrue : outputtrue->negate();
1772 Constraint * functionimplication=new Constraint(IMPLIES, new Constraint(AND, l, r), imp);
1773 ADDCONSTRAINT(functionimplication,"equalsimpl");
1781 void ConstGen::processFence(EPRecord *record) {
1782 //do we already account for the fence?
1783 if (isAlwaysExecuted(record))
1785 ExecPoint * record_ep=record->getEP();
1786 thread_id_t tid=record_ep->get_tid();
1787 uint thread=id_to_int(tid);
1788 ModelVector<EPRecord *> *tvec=(*threadactions)[thread];
1789 uint size=tvec->size();
1791 EPRecord *prevstore=NULL;
1793 for(i=0;i<size;i++) {
1794 EPRecord *rec=(*tvec)[i];
1795 if (rec->getType()==STORE) {
1798 if (rec == record) {
1803 if (prevstore == NULL) {
1807 EPRecord *rec=(*tvec)[i];
1808 if (rec->getType()==LOAD) {
1809 Constraint * condition=getExecutionConstraint(record);
1810 Constraint * storeload=getOrderConstraint(prevstore, rec);
1811 Constraint * c=new Constraint(IMPLIES, condition, storeload);
1812 ADDCONSTRAINT(c, "fence");
1819 /** processRecord performs actions on second traversal of event
1822 void ConstGen::processRecord(EPRecord *record) {
1823 switch (record->getType()) {
1825 processFunction(record);
1828 processEquals(record);
1831 processLoad(record);
1834 processStore(record);
1838 processFence(record);
1843 processFence(record);
1845 if (record->getOp()==ADD) {
1847 } else if (record->getOp()==CAS) {
1849 } else if (record->getOp()==EXC) {
1855 processYield(record);
1858 processBranch(record);
1865 /** visitRecord performs actions done on first traversal of event
1868 void ConstGen::visitRecord(EPRecord *record) {
1869 switch (record->getType()) {
1871 recordExecCond(record);
1872 insertEquals(record);
1875 recordExecCond(record);
1876 insertFunction(record);
1880 recordExecCond(record);
1881 insertAction(record);
1885 recordExecCond(record);
1886 insertAction(record);
1887 groupMemoryOperations(record);
1890 recordExecCond(record);
1891 insertAction(record);
1892 groupMemoryOperations(record);
1895 recordExecCond(record);
1896 insertAction(record);
1897 groupMemoryOperations(record);
1900 recordExecCond(record);
1901 insertBranch(record);
1904 recordExecCond(record);
1907 recordExecCond(record);
1908 insertNonLocal(record);
1911 insertLabel(record);
1914 recordExecCond(record);
1921 void ConstGen::recordExecCond(EPRecord *record) {
1922 ExecPoint *eprecord=record->getEP();
1923 EPValue * branchval=record->getBranch();
1924 EPRecord * branch=(branchval==NULL) ? NULL : branchval->getRecord();
1925 ExecPoint *epbranch= (branch==NULL) ? NULL : branch->getEP();
1926 RecordSet *srs=NULL;
1927 RecordIterator *sri=nonlocaltrans->iterator();
1928 while(sri->hasNext()) {
1929 EPRecord *nonlocal=sri->next();
1930 ExecPoint *epnl=nonlocal->getEP();
1931 if (epbranch!=NULL) {
1932 if (epbranch->compare(epnl)==CR_BEFORE) {
1933 //branch occurs after non local and thus will subsume condition
1934 //branch subsumes this condition
1938 if (eprecord->compare(epnl)==CR_BEFORE) {
1939 //record occurs after non-local, so add it to set
1941 srs=new RecordSet();
1947 execcondtable->put(record, srs);
1950 void ConstGen::insertNonLocal(EPRecord *record) {
1951 nonlocaltrans->add(record);
1954 void ConstGen::insertLabel(EPRecord *record) {
1955 RecordIterator *sri=nonlocaltrans->iterator();
1956 while(sri->hasNext()) {
1957 EPRecord *nonlocal=sri->next();
1958 if (nonlocal->getNextRecord()==record)
1965 void ConstGen::traverseRecord(EPRecord *record, bool initial) {
1968 visitRecord(record);
1970 processRecord(record);
1972 if (record->getType()==LOOPENTER) {
1973 workstack->push_back(record->getNextRecord());
1974 workstack->push_back(record->getChildRecord());
1977 if (record->getChildRecord()!=NULL) {
1978 workstack->push_back(record->getChildRecord());
1980 if (record->getType()==NONLOCALTRANS) {
1983 if (record->getType()==YIELD && model->params.noexecyields) {
1986 if (record->getType()==LOOPEXIT) {
1989 if (record->getType()==BRANCHDIR) {
1990 EPRecord *next=record->getNextRecord();
1992 workstack->push_back(next);
1993 for(uint i=0;i<record->numValues();i++) {
1994 EPValue *branchdir=record->getValue(i);
1996 //Could have an empty branch, so make sure the branch actually
1998 if (branchdir->getFirstRecord()!=NULL)
1999 workstack->push_back(branchdir->getFirstRecord());
2003 record=record->getNextRecord();
2004 } while(record!=NULL);
2007 unsigned int RecPairHash(RecPair *rp) {
2008 uintptr_t v=(uintptr_t) rp->epr1;
2009 uintptr_t v2=(uintptr_t) rp->epr2;
2012 return (uint)((x>>4)^(a));
2015 bool RecPairEquals(RecPair *r1, RecPair *r2) {
2016 return ((r1->epr1==r2->epr1)&&(r1->epr2==r2->epr2)) ||
2017 ((r1->epr1==r2->epr2)&&(r1->epr2==r2->epr1));