model: remove extraneous copy-and-paste
[c11tester.git] / model.cc
index d615e1ada44c7fa0af87478c14e04065ddf6387b..82b90601048845f32a9af77d57e938e8fb11450f 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -521,6 +521,7 @@ bool ModelChecker::next_execution()
 ModelAction * ModelChecker::get_last_conflict(ModelAction *act)
 {
        switch (act->get_type()) {
+       case ATOMIC_FENCE:
        case ATOMIC_READ:
        case ATOMIC_WRITE:
        case ATOMIC_RMW: {
@@ -1402,14 +1403,48 @@ bool ModelChecker::r_modification_order(ModelAction *curr, const ModelAction *rf
        bool added = false;
        ASSERT(curr->is_read());
 
+       /* Last SC fence in the current thread */
+       ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL);
+
        /* Iterate over all threads */
        for (i = 0; i < thrd_lists->size(); i++) {
+               /* Last SC fence in thread i */
+               ModelAction *last_sc_fence_thread_local = NULL;
+               if (int_to_id((int)i) != curr->get_tid())
+                       last_sc_fence_thread_local = get_last_seq_cst_fence(int_to_id(i), NULL);
+
+               /* Last SC fence in thread i, before last SC fence in current thread */
+               ModelAction *last_sc_fence_thread_before = NULL;
+               if (last_sc_fence_local)
+                       last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(i), last_sc_fence_local);
+
                /* Iterate over actions in thread, starting from most recent */
                action_list_t *list = &(*thrd_lists)[i];
                action_list_t::reverse_iterator rit;
                for (rit = list->rbegin(); rit != list->rend(); rit++) {
                        ModelAction *act = *rit;
 
+                       if (act->is_write() && act != rf && act != curr) {
+                               /* C++, Section 29.3 statement 5 */
+                               if (curr->is_seqcst() && last_sc_fence_thread_local &&
+                                               *act < *last_sc_fence_thread_local) {
+                                       mo_graph->addEdge(act, rf);
+                                       added = true;
+                               }
+                               /* C++, Section 29.3 statement 4 */
+                               else if (act->is_seqcst() && last_sc_fence_local &&
+                                               *act < *last_sc_fence_local) {
+                                       mo_graph->addEdge(act, rf);
+                                       added = true;
+                               }
+                               /* C++, Section 29.3 statement 6 */
+                               else if (last_sc_fence_thread_before &&
+                                               *act < *last_sc_fence_thread_before) {
+                                       mo_graph->addEdge(act, rf);
+                                       added = true;
+                               }
+                       }
+
                        /*
                         * Include at most one act per-thread that "happens
                         * before" curr. Don't consider reflexively.
@@ -1542,8 +1577,16 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                }
        }
 
+       /* Last SC fence in the current thread */
+       ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL);
+
        /* Iterate over all threads */
        for (i = 0; i < thrd_lists->size(); i++) {
+               /* Last SC fence in thread i, before last SC fence in current thread */
+               ModelAction *last_sc_fence_thread_before = NULL;
+               if (last_sc_fence_local && int_to_id((int)i) != curr->get_tid())
+                       last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(i), last_sc_fence_local);
+
                /* Iterate over actions in thread, starting from most recent */
                action_list_t *list = &(*thrd_lists)[i];
                action_list_t::reverse_iterator rit;
@@ -1570,6 +1613,13 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                                        continue;
                        }
 
+                       /* C++, Section 29.3 statement 7 */
+                       if (last_sc_fence_thread_before && act->is_write() &&
+                                       *act < *last_sc_fence_thread_before) {
+                               mo_graph->addEdge(act, curr);
+                               added = true;
+                       }
+
                        /*
                         * Include at most one act per-thread that "happens
                         * before" curr
@@ -1956,10 +2006,6 @@ void ModelChecker::add_action_to_lists(ModelAction *act)
                if (tid >= (int)vec->size())
                        vec->resize(priv->next_thread_id);
                (*vec)[tid].push_back(act);
-
-               if ((int)thrd_last_action->size() <= tid)
-                       thrd_last_action->resize(get_num_threads());
-               (*thrd_last_action)[tid] = act;
        }
 }
 
@@ -1997,6 +2043,35 @@ ModelAction * ModelChecker::get_last_seq_cst_write(ModelAction *curr) const
        return NULL;
 }
 
+/**
+ * Gets the last memory_order_seq_cst fence (in the total global sequence)
+ * performed in a particular thread, prior to a particular fence.
+ * @param tid The ID of the thread to check
+ * @param before_fence The fence from which to begin the search; if NULL, then
+ * search for the most recent fence in the thread.
+ * @return The last prior seq_cst fence in the thread, if exists; otherwise, NULL
+ */
+ModelAction * ModelChecker::get_last_seq_cst_fence(thread_id_t tid, const ModelAction *before_fence) const
+{
+       /* All fences should have NULL location */
+       action_list_t *list = get_safe_ptr_action(obj_map, NULL);
+       action_list_t::reverse_iterator rit = list->rbegin();
+
+       if (before_fence) {
+               for (; rit != list->rend(); rit++)
+                       if (*rit == before_fence)
+                               break;
+
+               ASSERT(*rit == before_fence);
+               rit++;
+       }
+
+       for (; rit != list->rend(); rit++)
+               if ((*rit)->is_fence() && (tid == (*rit)->get_tid()) && (*rit)->is_seqcst())
+                       return *rit;
+       return NULL;
+}
+
 /**
  * Gets the last unlock operation performed on a particular mutex (i.e., memory
  * location). This function identifies the mutex according to the current
@@ -2234,16 +2309,16 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
        unsigned int i;
        ASSERT(curr->is_read());
 
-       ModelAction *last_seq_cst = NULL;
+       ModelAction *last_sc_write = NULL;
 
        /* Track whether this object has been initialized */
        bool initialized = false;
 
        if (curr->is_seqcst()) {
-               last_seq_cst = get_last_seq_cst_write(curr);
+               last_sc_write = get_last_seq_cst_write(curr);
                /* We have to at least see the last sequentially consistent write,
                         so we are initialized. */
-               if (last_seq_cst != NULL)
+               if (last_sc_write != NULL)
                        initialized = true;
        }
 
@@ -2260,15 +2335,20 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
                                continue;
 
                        /* Don't consider more than one seq_cst write if we are a seq_cst read. */
-                       if (!curr->is_seqcst() || (!act->is_seqcst() && (last_seq_cst == NULL || !act->happens_before(last_seq_cst))) || act == last_seq_cst) {
-                               if (!curr->get_sleep_flag() || curr->is_seqcst() || sleep_can_read_from(curr, act)) {
-                                       DEBUG("Adding action to may_read_from:\n");
-                                       if (DBG_ENABLED()) {
-                                               act->print();
-                                               curr->print();
-                                       }
-                                       curr->get_node()->add_read_from(act);
+                       bool allow_read = true;
+
+                       if (curr->is_seqcst() && (act->is_seqcst() || (last_sc_write != NULL && act->happens_before(last_sc_write))) && act != last_sc_write)
+                               allow_read = false;
+                       else if (curr->get_sleep_flag() && !curr->is_seqcst() && !sleep_can_read_from(curr, act))
+                               allow_read = false;
+
+                       if (allow_read) {
+                               DEBUG("Adding action to may_read_from:\n");
+                               if (DBG_ENABLED()) {
+                                       act->print();
+                                       curr->print();
                                }
+                               curr->get_node()->add_read_from(act);
                        }
 
                        /* Include at most one act per-thread that "happens before" curr */