Tiago Mück has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/27132 )

Change subject: cpu-o3: MemDepUnit tracks load-acquire/store-release
......................................................................

cpu-o3: MemDepUnit tracks load-acquire/store-release

MemDepUnit tracks loads/stores that are also barriers, which is the case
of load-acquire / store-release instructions. The tracking logic is also
extended to consider multiple outstanding barriers.

Change-Id: I95b0c710d7c7e4a138492177e3eaaf5143e9a0ba
Signed-off-by: Tiago Mück <tiago.m...@arm.com>
---
M src/cpu/o3/mem_dep_unit.hh
M src/cpu/o3/mem_dep_unit_impl.hh
2 files changed, 118 insertions(+), 73 deletions(-)



diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh
index c4a3310..54d2363 100644
--- a/src/cpu/o3/mem_dep_unit.hh
+++ b/src/cpu/o3/mem_dep_unit.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014 ARM Limited
+ * Copyright (c) 2012, 2014, 2020 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -45,6 +45,7 @@
 #include <memory>
 #include <set>
 #include <unordered_map>
+#include <unordered_set>

 #include "base/statistics.hh"
 #include "cpu/inst_seq.hh"
@@ -177,7 +178,7 @@
       public:
         /** Constructs a memory dependence entry. */
         MemDepEntry(const DynInstPtr &new_inst)
-            : inst(new_inst), regsReady(false), memDepReady(false),
+            : inst(new_inst), regsReady(false), memDeps(0),
               completed(false), squashed(false)
         {
 #ifdef DEBUG
@@ -216,8 +217,8 @@

         /** If the registers are ready or not. */
         bool regsReady;
-        /** If all memory dependencies have been satisfied. */
-        bool memDepReady;
+        /** Number of memory dependencies that need to be satisfied. */
+        int memDeps;
         /** If the instruction is completed. */
         bool completed;
         /** If the instruction is squashed. */
@@ -257,14 +258,22 @@
      */
     MemDepPred depPred;

+    /** Sequence numbers of outstanding load barriers. */
+    std::unordered_set<InstSeqNum> loadBarrierSNs;
+
+    /** Sequence numbers of outstanding store barriers. */
+    std::unordered_set<InstSeqNum> storeBarrierSNs;
+
     /** Is there an outstanding load barrier that loads must wait on. */
-    bool loadBarrier;
-    /** The sequence number of the load barrier. */
-    InstSeqNum loadBarrierSN;
+    bool loadBarrier() { return loadBarrierSNs.size() != 0; }
+
     /** Is there an outstanding store barrier that loads must wait on. */
-    bool storeBarrier;
-    /** The sequence number of the store barrier. */
-    InstSeqNum storeBarrierSN;
+    bool storeBarrier() { return storeBarrierSNs.size() != 0; }
+
+    void _insertBarrier(const DynInstPtr &barr_inst);
+
+    void _completeBarrier(const DynInstPtr &inst);
+

     /** Pointer to the IQ. */
     InstructionQueue<Impl> *iqPtr;
diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh
index c712965..6fa1607 100644
--- a/src/cpu/o3/mem_dep_unit_impl.hh
+++ b/src/cpu/o3/mem_dep_unit_impl.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014 ARM Limited
+ * Copyright (c) 2012, 2014, 2020 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -42,6 +42,7 @@
 #define __CPU_O3_MEM_DEP_UNIT_IMPL_HH__

 #include <map>
+#include <vector>

 #include "cpu/o3/inst_queue.hh"
 #include "cpu/o3/mem_dep_unit.hh"
@@ -50,8 +51,7 @@

 template <class MemDepPred, class Impl>
 MemDepUnit<MemDepPred, Impl>::MemDepUnit()
-    : loadBarrier(false), loadBarrierSN(0), storeBarrier(false),
-      storeBarrierSN(0), iqPtr(NULL)
+    : iqPtr(NULL)
 {
 }

@@ -60,8 +60,7 @@
     : _name(params->name + ".memdepunit"),
       depPred(params->store_set_clear_period, params->SSITSize,
               params->LFSTSize),
-      loadBarrier(false), loadBarrierSN(0), storeBarrier(false),
-      storeBarrierSN(0), iqPtr(NULL)
+      iqPtr(NULL)
 {
     DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n");
 }
@@ -155,8 +154,8 @@
 MemDepUnit<MemDepPred, Impl>::takeOverFrom()
 {
     // Be sure to reset all state.
-    loadBarrier = storeBarrier = false;
-    loadBarrierSN = storeBarrierSN = 0;
+    loadBarrierSNs.clear();
+    storeBarrierSNs.clear();
     depPred.clear();
 }

@@ -169,6 +168,48 @@

 template <class MemDepPred, class Impl>
 void
+MemDepUnit<MemDepPred, Impl>::_insertBarrier(const DynInstPtr &barr_inst)
+{
+    InstSeqNum barr_sn = barr_inst->seqNum;
+    // Memory barriers block loads and stores, write barriers only stores.
+    if (barr_inst->isMemBarrier()) {
+        loadBarrierSNs.insert(barr_sn);
+        storeBarrierSNs.insert(barr_sn);
+        DPRINTF(MemDepUnit, "Inserted a memory barrier %s SN:%lli\n",
+                barr_inst->pcState(),barr_sn);
+    } else if (barr_inst->isWriteBarrier()) {
+        storeBarrierSNs.insert(barr_sn);
+        DPRINTF(MemDepUnit, "Inserted a write barrier %s SN:%lli\n",
+                barr_inst->pcState(),barr_sn);
+    }
+    if (loadBarrierSNs.size() || storeBarrierSNs.size())
+        DPRINTF(MemDepUnit, "Outstanding load barriers = %d; "
+                            "store barriers = %d\n",
+                loadBarrierSNs.size(), storeBarrierSNs.size());
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::_completeBarrier(const DynInstPtr &inst)
+{
+    InstSeqNum barr_sn = inst->seqNum;
+    if (inst->isMemBarrier()) {
+        assert(loadBarrier());
+        assert(storeBarrier());
+        loadBarrierSNs.erase(barr_sn);
+        storeBarrierSNs.erase(barr_sn);
+        DPRINTF(MemDepUnit, "Memory barrier completed: %s SN:%lli\n",
+                            inst->pcState(), inst->seqNum);
+    } else if (inst->isWriteBarrier()) {
+        assert(storeBarrier());
+        storeBarrierSNs.erase(barr_sn);
+        DPRINTF(MemDepUnit, "Write barrier completed: %s SN:%lli\n",
+                            inst->pcState(), inst->seqNum);
+    }
+}
+
+template <class MemDepPred, class Impl>
+void
 MemDepUnit<MemDepPred, Impl>::insert(const DynInstPtr &inst)
 {
     ThreadID tid = inst->threadNumber;
@@ -188,39 +229,46 @@

     // Check any barriers and the dependence predictor for any
     // producing memrefs/stores.
-    InstSeqNum producing_store;
-    if ((inst->isLoad() || inst->isAtomic()) && loadBarrier) {
-        DPRINTF(MemDepUnit, "Load barrier [sn:%lli] in flight\n",
-                loadBarrierSN);
-        producing_store = loadBarrierSN;
-    } else if ((inst->isStore() || inst->isAtomic()) && storeBarrier) {
-        DPRINTF(MemDepUnit, "Store barrier [sn:%lli] in flight\n",
-                storeBarrierSN);
-        producing_store = storeBarrierSN;
+    std::vector<InstSeqNum>  producing_stores;
+    if ((inst->isLoad() || inst->isAtomic()) && loadBarrier()) {
+        DPRINTF(MemDepUnit, "%d load barriers in flight\n",
+                loadBarrierSNs.size());
+        producing_stores.insert(std::end(producing_stores),
+                                std::begin(loadBarrierSNs),
+                                std::end(loadBarrierSNs));
+    } else if ((inst->isStore() || inst->isAtomic()) && storeBarrier()) {
+        DPRINTF(MemDepUnit, "%d store barriers in flight\n",
+                storeBarrierSNs.size());
+        producing_stores.insert(std::end(producing_stores),
+                                std::begin(storeBarrierSNs),
+                                std::end(storeBarrierSNs));
     } else {
-        producing_store = depPred.checkInst(inst->instAddr());
+        InstSeqNum dep = depPred.checkInst(inst->instAddr());
+        if (dep != 0)
+            producing_stores.push_back(dep);
     }

-    MemDepEntryPtr store_entry = NULL;
+    std::vector<MemDepEntryPtr> store_entries;

     // If there is a producing store, try to find the entry.
-    if (producing_store != 0) {
-        DPRINTF(MemDepUnit, "Searching for producer\n");
+    for (auto producing_store : producing_stores) {
+        DPRINTF(MemDepUnit, "Searching for producer [sn:%lli]\n",
+                            producing_store);
         MemDepHashIt hash_it = memDepHash.find(producing_store);

         if (hash_it != memDepHash.end()) {
-            store_entry = (*hash_it).second;
-            DPRINTF(MemDepUnit, "Proucer found\n");
+            store_entries.push_back((*hash_it).second);
+            DPRINTF(MemDepUnit, "Producer found\n");
         }
     }

// If no store entry, then instruction can issue as soon as the registers
     // are ready.
-    if (!store_entry) {
+    if (store_entries.size() == 0) {
         DPRINTF(MemDepUnit, "No dependency for inst PC "
                 "%s [sn:%lli].\n", inst->pcState(), inst->seqNum);

-        inst_entry->memDepReady = true;
+        assert(inst_entry->memDeps == 0);

         if (inst->readyToIssue()) {
             inst_entry->regsReady = true;
@@ -229,8 +277,9 @@
         }
     } else {
         // Otherwise make the instruction dependent on the store/barrier.
-        DPRINTF(MemDepUnit, "Adding to dependency list; "
-                "inst PC %s is dependent on [sn:%lli].\n",
+        DPRINTF(MemDepUnit, "Adding to dependency list\n");
+        for (auto producing_store : producing_stores)
+ DPRINTF(MemDepUnit, "\tinst PC %s is dependent on [sn:%lli].\n",
                 inst->pcState(), producing_store);

         if (inst->readyToIssue()) {
@@ -241,7 +290,10 @@
         inst->clearCanIssue();

         // Add this instruction to the list of dependents.
-        store_entry->dependInsts.push_back(inst_entry);
+        for (auto store_entry : store_entries)
+            store_entry->dependInsts.push_back(inst_entry);
+
+        inst_entry->memDeps = store_entries.size();

         if (inst->isLoad()) {
             ++conflictingLoads;
@@ -250,6 +302,9 @@
         }
     }

+    // for load-acquire store-release that could also be a barrier
+    _insertBarrier(inst);
+
     if (inst->isStore() || inst->isAtomic()) {
         DPRINTF(MemDepUnit, "Inserting store/atomic PC %s [sn:%lli].\n",
                 inst->pcState(), inst->seqNum);
@@ -298,26 +353,16 @@
     } else {
         panic("Unknown type! (most likely a barrier).");
     }
+
+    // for load-acquire store-release that could also be a barrier
+    _insertBarrier(inst);
 }

 template <class MemDepPred, class Impl>
 void
 MemDepUnit<MemDepPred, Impl>::insertBarrier(const DynInstPtr &barr_inst)
 {
-    InstSeqNum barr_sn = barr_inst->seqNum;
-    // Memory barriers block loads and stores, write barriers only stores.
-    if (barr_inst->isMemBarrier()) {
-        loadBarrier = true;
-        loadBarrierSN = barr_sn;
-        storeBarrier = true;
-        storeBarrierSN = barr_sn;
-        DPRINTF(MemDepUnit, "Inserted a memory barrier %s SN:%lli\n",
-                barr_inst->pcState(),barr_sn);
-    } else if (barr_inst->isWriteBarrier()) {
-        storeBarrier = true;
-        storeBarrierSN = barr_sn;
-        DPRINTF(MemDepUnit, "Inserted a write barrier\n");
-    }
+    _insertBarrier(barr_inst);

     ThreadID tid = barr_inst->threadNumber;

@@ -325,7 +370,7 @@

     // Add the MemDepEntry to the hash.
     memDepHash.insert(
-        std::pair<InstSeqNum, MemDepEntryPtr>(barr_sn, inst_entry));
+ std::pair<InstSeqNum, MemDepEntryPtr>(barr_inst->seqNum, inst_entry));
 #ifdef DEBUG
     MemDepEntry::memdep_insert++;
 #endif
@@ -348,7 +393,7 @@

     inst_entry->regsReady = true;

-    if (inst_entry->memDepReady) {
+    if (inst_entry->memDeps == 0) {
         DPRINTF(MemDepUnit, "Instruction has its memory "
                 "dependencies resolved, adding it to the ready list.\n");

@@ -422,6 +467,9 @@
 #ifdef DEBUG
     MemDepEntry::memdep_erase++;
 #endif
+
+    // Check barrier
+    _completeBarrier(inst);
 }

 template <class MemDepPred, class Impl>
@@ -430,19 +478,6 @@
 {
     wakeDependents(inst);
     completed(inst);
-
-    InstSeqNum barr_sn = inst->seqNum;
-    DPRINTF(MemDepUnit, "barrier completed: %s SN:%lli\n", inst->pcState(),
-            inst->seqNum);
-    if (inst->isMemBarrier()) {
-        if (loadBarrierSN == barr_sn)
-            loadBarrier = false;
-        if (storeBarrierSN == barr_sn)
-            storeBarrier = false;
-    } else if (inst->isWriteBarrier()) {
-        if (storeBarrierSN == barr_sn)
-            storeBarrier = false;
-    }
 }

 template <class MemDepPred, class Impl>
@@ -469,10 +504,13 @@
                 "[sn:%lli].\n",
                 woken_inst->inst->seqNum);

-        if (woken_inst->regsReady && !woken_inst->squashed) {
+        assert(woken_inst->memDeps > 0);
+        woken_inst->memDeps -= 1;
+
+        if ((woken_inst->memDeps == 0) &&
+            woken_inst->regsReady &&
+            !woken_inst->squashed) {
             moveToReady(woken_inst);
-        } else {
-            woken_inst->memDepReady = true;
         }
     }

@@ -507,11 +545,9 @@
         DPRINTF(MemDepUnit, "Squashing inst [sn:%lli]\n",
                 (*squash_it)->seqNum);

-        if ((*squash_it)->seqNum == loadBarrierSN)
-              loadBarrier = false;
+        loadBarrierSNs.erase((*squash_it)->seqNum);

-        if ((*squash_it)->seqNum == storeBarrierSN)
-              storeBarrier = false;
+        storeBarrierSNs.erase((*squash_it)->seqNum);

         hash_it = memDepHash.find((*squash_it)->seqNum);


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/27132
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I95b0c710d7c7e4a138492177e3eaaf5143e9a0ba
Gerrit-Change-Number: 27132
Gerrit-PatchSet: 1
Gerrit-Owner: Tiago Mück <tiago.m...@arm.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to