39#include "debug/MemDepUnit.hh"
40#include "params/BaseO3CPU.hh"
49int MemDepUnit::MemDepEntry::memdep_count = 0;
50int MemDepUnit::MemDepEntry::memdep_insert = 0;
51int MemDepUnit::MemDepEntry::memdep_erase = 0;
58 depPred(
_name +
".storesets", params.store_set_clear_period,
59 params.SSITSize, params.SSITAssoc, params.SSITReplPolicy,
60 params.SSITIndexingPolicy, params.LFSTSize),
76 hash_it =
memDepHash.find((*inst_list_it)->seqNum);
87 assert(MemDepEntry::memdep_count == 0);
100 depPred.init(params.store_set_clear_period,
101 params.SSITSize, params.SSITAssoc, params.SSITReplPolicy,
102 params.SSITIndexingPolicy, params.LFSTSize);
104 std::string stats_group_name =
csprintf(
"MemDepUnit__%i", tid);
111 "Number of loads inserted to the mem dependence unit."),
113 "Number of stores inserted to the mem dependence unit."),
115 "Number of conflicting loads."),
117 "Number of conflicting stores.")
128 drained = drained &&
instList[
i].empty();
164 if (barr_inst->isReadBarrier() || barr_inst->isHtmCmd())
166 if (barr_inst->isWriteBarrier() || barr_inst->isHtmCmd())
169 if (debug::MemDepUnit) {
170 const char *barrier_type =
nullptr;
171 if (barr_inst->isReadBarrier() && barr_inst->isWriteBarrier())
172 barrier_type =
"memory";
173 else if (barr_inst->isReadBarrier())
174 barrier_type =
"read";
175 else if (barr_inst->isWriteBarrier())
176 barrier_type =
"write";
180 barrier_type, barr_inst->pcState(), barr_sn);
185 "store barriers = %d\n",
202 MemDepEntry::memdep_insert++;
207 inst_entry->listIt = --(
instList[tid].end());
215 producing_stores.insert(std::end(producing_stores),
218 }
else if ((inst->isStore() || inst->isAtomic()) &&
hasStoreBarrier()) {
221 producing_stores.insert(std::end(producing_stores),
227 producing_stores.push_back(dep);
233 for (
auto producing_store : producing_stores) {
239 store_entries.push_back((*hash_it).second);
246 if (store_entries.empty()) {
248 "%s [sn:%lli].\n", inst->pcState(), inst->seqNum);
250 assert(inst_entry->memDeps == 0);
252 if (inst->readyToIssue()) {
253 inst_entry->regsReady =
true;
260 for ([[maybe_unused]]
auto producing_store : producing_stores)
262 inst->pcState(), producing_store);
264 if (inst->readyToIssue()) {
265 inst_entry->regsReady =
true;
269 inst->clearCanIssue();
272 for (
auto store_entry : store_entries)
273 store_entry->dependInsts.push_back(inst_entry);
275 inst_entry->memDeps = store_entries.size();
277 if (inst->isLoad()) {
278 ++
stats.conflictingLoads;
280 ++
stats.conflictingStores;
287 if (inst->isStore() || inst->isAtomic()) {
289 inst->pcState(), inst->seqNum);
291 depPred.insertStore(inst->pcState().instAddr(), inst->seqNum,
294 ++
stats.insertedStores;
295 }
else if (inst->isLoad()) {
296 ++
stats.insertedLoads;
298 panic(
"Unknown type! (most likely a barrier).");
309 if (inst->isStore() || inst->isAtomic()) {
311 inst->pcState(), inst->seqNum);
313 depPred.insertStore(inst->pcState().instAddr(), inst->seqNum,
316 ++
stats.insertedStores;
317 }
else if (inst->isLoad()) {
318 ++
stats.insertedLoads;
320 panic(
"Unknown type! (most likely a barrier).");
327 ThreadID tid = barr_inst->threadNumber;
329 MemDepEntryPtr inst_entry = std::make_shared<MemDepEntry>(barr_inst);
335 MemDepEntry::memdep_insert++;
341 inst_entry->listIt = --(
instList[tid].end());
350 "instruction PC %s [sn:%lli].\n",
351 inst->pcState(), inst->seqNum);
355 inst_entry->regsReady =
true;
357 if (inst_entry->memDeps == 0) {
359 "dependencies resolved, adding it to the ready list.\n");
364 "memory dependency.\n");
372 "instruction PC %s as ready [sn:%lli].\n",
373 inst->pcState(), inst->seqNum);
398 temp_inst->pcState(), temp_inst->seqNum);
410 inst->pcState(), inst->seqNum);
419 instList[tid].erase((*hash_it).second->listIt);
421 (*hash_it).second = NULL;
425 MemDepEntry::memdep_erase++;
436 if (inst->isWriteBarrier() || inst->isHtmCmd()) {
440 if (inst->isReadBarrier() || inst->isHtmCmd()) {
444 if (debug::MemDepUnit) {
445 const char *barrier_type =
nullptr;
446 if (inst->isWriteBarrier() && inst->isReadBarrier())
447 barrier_type =
"Memory";
448 else if (inst->isWriteBarrier())
449 barrier_type =
"Write";
450 else if (inst->isReadBarrier())
451 barrier_type =
"Read";
455 barrier_type, inst->pcState(), inst->seqNum);
464 if (!inst->isStore() && !inst->isAtomic() && !inst->isReadBarrier() &&
465 !inst->isWriteBarrier() && !inst->isHtmCmd()) {
471 for (
int i = 0;
i < inst_entry->dependInsts.size(); ++
i ) {
474 if (!woken_inst->inst) {
481 woken_inst->inst->seqNum);
483 assert(woken_inst->memDeps > 0);
484 woken_inst->memDeps -= 1;
486 if ((woken_inst->memDeps == 0) &&
487 woken_inst->regsReady &&
488 !woken_inst->squashed) {
493 inst_entry->dependInsts.clear();
503 "Memory dependency entry created. memdep_count=%i %s\n",
504 memdep_count,
inst->pcState());
517 "Memory dependency entry deleted. memdep_count=%i %s\n",
518 memdep_count,
inst->pcState());
528 if ((*replay_it)->threadNumber == tid &&
529 (*replay_it)->seqNum > squashed_num) {
543 (*squash_it)->seqNum > squashed_num) {
546 (*squash_it)->seqNum);
552 hash_it =
memDepHash.find((*squash_it)->seqNum);
556 (*hash_it).second->squashed =
true;
558 (*hash_it).second = NULL;
562 MemDepEntry::memdep_erase++;
569 depPred.squash(squashed_num, tid);
577 " load: %#x, store: %#x\n", violating_load->pcState().instAddr(),
578 store_inst->pcState().instAddr());
580 depPred.violation(store_inst->pcState().instAddr(),
581 violating_load->pcState().instAddr());
588 inst->pcState().instAddr(), inst->seqNum);
590 depPred.issued(inst->pcState().instAddr(), inst->seqNum, inst->isStore());
600 return (*hash_it).second;
607 "to the ready list.\n", woken_inst_entry->inst->seqNum);
609 assert(!woken_inst_entry->squashed);
611 iqPtr->addReadyMemInst(woken_inst_entry->inst);
619 cprintf(
"Instruction list %i size: %i\n",
625 while (inst_list_it !=
instList[tid].end()) {
626 cprintf(
"Instruction:%i\nPC: %s\n[sn:%llu]\n[tid:%i]\nIssued:%i\n"
628 num, (*inst_list_it)->pcState(),
629 (*inst_list_it)->seqNum,
630 (*inst_list_it)->threadNumber,
631 (*inst_list_it)->isIssued(),
632 (*inst_list_it)->isSquashed());
641 cprintf(
"Memory dependence entries: %i\n", MemDepEntry::memdep_count);
O3CPU class, has each of the stages (fetch through commit) within it, as well as all of the time buff...
A standard instruction queue class.
std::vector< MemDepEntryPtr > dependInsts
A vector of any dependent instructions.
~MemDepEntry()
Frees any pointers.
MemDepEntry(const DynInstPtr &new_inst)
Constructs a memory dependence entry.
DynInstPtr inst
The instruction being tracked.
bool isDrained() const
Determine if we are drained.
void completeInst(const DynInstPtr &inst)
Notifies completion of an instruction.
std::string name() const
Returns the name of the memory dependence unit.
void takeOverFrom()
Takes over from another CPU's thread.
std::list< DynInstPtr > instList[MaxThreads]
A list of all instructions in the memory dependence unit.
void moveToReady(MemDepEntryPtr &ready_inst_entry)
Moves an entry to the ready list.
bool hasStoreBarrier() const
Is there an outstanding store barrier that loads must wait on.
void nonSpecInstReady(const DynInstPtr &inst)
Indicate that a non-speculative instruction is ready.
std::shared_ptr< MemDepEntry > MemDepEntryPtr
std::list< DynInstPtr >::iterator ListIt
MemDepUnit()
Empty constructor.
void completed(const DynInstPtr &inst)
Completes a memory instruction.
~MemDepUnit()
Frees up any memory allocated.
void dumpLists()
Debugging function to dump the lists of instructions.
std::unordered_set< InstSeqNum > loadBarrierSNs
Sequence numbers of outstanding load barriers.
void issue(const DynInstPtr &inst)
Issues the given instruction.
void insert(const DynInstPtr &inst)
Inserts a memory instruction.
void squash(const InstSeqNum &squashed_num, ThreadID tid)
Squashes all instructions up until a given sequence number for a specific thread.
void violation(const DynInstPtr &store_inst, const DynInstPtr &violating_load)
Indicates an ordering violation between a store and a younger load.
StoreSet depPred
The memory dependence predictor.
void replay()
Replays all instructions that have been rescheduled by moving them to the ready list.
void wakeDependents(const DynInstPtr &inst)
Wakes any dependents of a memory instruction.
void init(const BaseO3CPUParams ¶ms, ThreadID tid, CPU *cpu)
Initializes the unit with parameters and a thread id.
MemDepHash memDepHash
A hash map of all memory dependence entries.
std::list< DynInstPtr > instsToReplay
A list of all instructions that are going to be replayed.
void regsReady(const DynInstPtr &inst)
Indicate that an instruction has its registers ready.
void insertBarrierSN(const DynInstPtr &barr_inst)
Inserts the SN of a barrier inst.
std::unordered_set< InstSeqNum > storeBarrierSNs
Sequence numbers of outstanding store barriers.
bool hasLoadBarrier() const
Is there an outstanding load barrier that loads must wait on.
MemDepEntryPtr & findInHash(const DynInstConstPtr &inst)
Finds the memory dependence entry in the hash map.
InstructionQueue * iqPtr
Pointer to the IQ.
MemDepHash::iterator MemDepHashIt
gem5::o3::MemDepUnit::MemDepUnitStats stats
void insertNonSpec(const DynInstPtr &inst)
Inserts a non-speculative memory instruction.
void drainSanityCheck() const
Perform sanity checks after a drain.
void reschedule(const DynInstPtr &inst)
Reschedules an instruction to be re-executed.
void insertBarrier(const DynInstPtr &barr_inst)
Inserts a barrier instruction.
void setIQ(InstructionQueue *iq_ptr)
Sets the pointer to the IQ.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
#define panic(...)
This implements a cprintf based panic() function.
void addStatGroup(const char *name, Group *block)
Add a stat block as a child of this block.
static constexpr int MaxThreads
RefCountingPtr< DynInst > DynInstPtr
RefCountingPtr< const DynInst > DynInstConstPtr
Copyright (c) 2024 Arm Limited All rights reserved.
int16_t ThreadID
Thread index/ID type.
void cprintf(const char *format, const Args &...args)
std::string csprintf(const char *format, const Args &...args)
statistics::Scalar conflictingLoads
Stat for number of conflicting loads that had to wait for a store.
MemDepUnitStats(statistics::Group *parent)
statistics::Scalar conflictingStores
Stat for number of conflicting stores that had to wait for a store.
statistics::Scalar insertedLoads
Stat for number of inserted loads.
statistics::Scalar insertedStores
Stat for number of inserted stores.