/*
- * 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
#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"
template <class MemDepPred, class Impl>
MemDepUnit<MemDepPred, Impl>::MemDepUnit()
- : loadBarrier(false), loadBarrierSN(0), storeBarrier(false),
- storeBarrierSN(0), iqPtr(NULL)
+ : iqPtr(NULL)
{
}
: _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");
}
MemDepUnit<MemDepPred, Impl>::takeOverFrom()
{
// Be sure to reset all state.
- loadBarrier = storeBarrier = false;
- loadBarrierSN = storeBarrierSN = 0;
+ loadBarrierSNs.clear();
+ storeBarrierSNs.clear();
depPred.clear();
}
iqPtr = iq_ptr;
}
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::insertBarrierSN(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>::insert(const DynInstPtr &inst)
// 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()) && hasLoadBarrier()) {
+ 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()) && hasStoreBarrier()) {
+ 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.empty()) {
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;
}
} 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()) {
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;
}
}
+ // for load-acquire store-release that could also be a barrier
+ insertBarrierSN(inst);
+
if (inst->isStore() || inst->isAtomic()) {
DPRINTF(MemDepUnit, "Inserting store/atomic PC %s [sn:%lli].\n",
inst->pcState(), inst->seqNum);
void
MemDepUnit<MemDepPred, Impl>::insertNonSpec(const DynInstPtr &inst)
{
- ThreadID tid = inst->threadNumber;
-
- MemDepEntryPtr inst_entry = std::make_shared<MemDepEntry>(inst);
-
- // Insert the MemDepEntry into the hash.
- memDepHash.insert(
- std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry));
-#ifdef DEBUG
- MemDepEntry::memdep_insert++;
-#endif
-
- // Add the instruction to the list.
- instList[tid].push_back(inst);
-
- inst_entry->listIt = --(instList[tid].end());
+ insertBarrier(inst);
// Might want to turn this part into an inline function or something.
// It's shared between both insert functions.
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");
- }
-
ThreadID tid = barr_inst->threadNumber;
MemDepEntryPtr inst_entry = std::make_shared<MemDepEntry>(barr_inst);
// 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
instList[tid].push_back(barr_inst);
inst_entry->listIt = --(instList[tid].end());
+
+ insertBarrierSN(barr_inst);
}
template <class MemDepPred, class Impl>
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");
{
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;
+ assert(hasLoadBarrier());
+ assert(hasStoreBarrier());
+ 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()) {
- if (storeBarrierSN == barr_sn)
- storeBarrier = false;
+ assert(hasStoreBarrier());
+ storeBarrierSNs.erase(barr_sn);
+ DPRINTF(MemDepUnit, "Write barrier completed: %s SN:%lli\n",
+ inst->pcState(), inst->seqNum);
}
}
"[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;
}
}
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);