40#include "debug/MemDepUnit.hh"
41#include "params/BaseO3CPU.hh"
50int MemDepUnit::MemDepEntry::memdep_count = 0;
51int MemDepUnit::MemDepEntry::memdep_insert = 0;
52int MemDepUnit::MemDepEntry::memdep_erase = 0;
58 : _name(params.
name +
".memdepunit"),
59 depPred(params.store_set_clear_period, params.SSITSize,
76 hash_it =
memDepHash.find((*inst_list_it)->seqNum);
87 assert(MemDepEntry::memdep_count == 0);
99 depPred.
init(params.store_set_clear_period, params.SSITSize,
102 std::string stats_group_name =
csprintf(
"MemDepUnit__%i", tid);
107 : statistics::
Group(parent),
108 ADD_STAT(insertedLoads, statistics::units::Count::get(),
109 "Number of loads inserted to the mem dependence unit."),
110 ADD_STAT(insertedStores, statistics::units::Count::get(),
111 "Number of stores inserted to the mem dependence unit."),
112 ADD_STAT(conflictingLoads, statistics::units::Count::get(),
113 "Number of conflicting loads."),
114 ADD_STAT(conflictingStores, statistics::units::Count::get(),
115 "Number of conflicting stores.")
126 drained = drained &&
instList[
i].empty();
162 if (barr_inst->isReadBarrier() || barr_inst->isHtmCmd())
164 if (barr_inst->isWriteBarrier() || barr_inst->isHtmCmd())
167 if (debug::MemDepUnit) {
168 const char *barrier_type =
nullptr;
169 if (barr_inst->isReadBarrier() && barr_inst->isWriteBarrier())
170 barrier_type =
"memory";
171 else if (barr_inst->isReadBarrier())
172 barrier_type =
"read";
173 else if (barr_inst->isWriteBarrier())
174 barrier_type =
"write";
178 barrier_type, barr_inst->pcState(), barr_sn);
183 "store barriers = %d\n",
200 MemDepEntry::memdep_insert++;
205 inst_entry->listIt = --(
instList[tid].end());
213 producing_stores.insert(std::end(producing_stores),
216 }
else if ((inst->isStore() || inst->isAtomic()) &&
hasStoreBarrier()) {
219 producing_stores.insert(std::end(producing_stores),
225 producing_stores.push_back(dep);
231 for (
auto producing_store : producing_stores) {
237 store_entries.push_back((*hash_it).second);
244 if (store_entries.empty()) {
246 "%s [sn:%lli].\n", inst->pcState(), inst->seqNum);
248 assert(inst_entry->memDeps == 0);
250 if (inst->readyToIssue()) {
251 inst_entry->regsReady =
true;
258 for ([[maybe_unused]]
auto producing_store : producing_stores)
260 inst->pcState(), producing_store);
262 if (inst->readyToIssue()) {
263 inst_entry->regsReady =
true;
267 inst->clearCanIssue();
270 for (
auto store_entry : store_entries)
271 store_entry->dependInsts.push_back(inst_entry);
273 inst_entry->memDeps = store_entries.size();
275 if (inst->isLoad()) {
285 if (inst->isStore() || inst->isAtomic()) {
287 inst->pcState(), inst->seqNum);
293 }
else if (inst->isLoad()) {
296 panic(
"Unknown type! (most likely a barrier).");
307 if (inst->isStore() || inst->isAtomic()) {
309 inst->pcState(), inst->seqNum);
315 }
else if (inst->isLoad()) {
318 panic(
"Unknown type! (most likely a barrier).");
325 ThreadID tid = barr_inst->threadNumber;
327 MemDepEntryPtr inst_entry = std::make_shared<MemDepEntry>(barr_inst);
333 MemDepEntry::memdep_insert++;
339 inst_entry->listIt = --(
instList[tid].end());
348 "instruction PC %s [sn:%lli].\n",
349 inst->pcState(), inst->seqNum);
353 inst_entry->regsReady =
true;
355 if (inst_entry->memDeps == 0) {
357 "dependencies resolved, adding it to the ready list.\n");
362 "memory dependency.\n");
370 "instruction PC %s as ready [sn:%lli].\n",
371 inst->pcState(), inst->seqNum);
396 temp_inst->pcState(), temp_inst->seqNum);
408 inst->pcState(), inst->seqNum);
417 instList[tid].erase((*hash_it).second->listIt);
419 (*hash_it).second = NULL;
423 MemDepEntry::memdep_erase++;
434 if (inst->isWriteBarrier() || inst->isHtmCmd()) {
438 if (inst->isReadBarrier() || inst->isHtmCmd()) {
442 if (debug::MemDepUnit) {
443 const char *barrier_type =
nullptr;
444 if (inst->isWriteBarrier() && inst->isReadBarrier())
445 barrier_type =
"Memory";
446 else if (inst->isWriteBarrier())
447 barrier_type =
"Write";
448 else if (inst->isReadBarrier())
449 barrier_type =
"Read";
453 barrier_type, inst->pcState(), inst->seqNum);
462 if (!inst->isStore() && !inst->isAtomic() && !inst->isReadBarrier() &&
463 !inst->isWriteBarrier() && !inst->isHtmCmd()) {
469 for (
int i = 0;
i < inst_entry->dependInsts.size(); ++
i ) {
472 if (!woken_inst->inst) {
479 woken_inst->inst->seqNum);
481 assert(woken_inst->memDeps > 0);
482 woken_inst->memDeps -= 1;
484 if ((woken_inst->memDeps == 0) &&
485 woken_inst->regsReady &&
486 !woken_inst->squashed) {
491 inst_entry->dependInsts.clear();
501 "Memory dependency entry created. memdep_count=%i %s\n",
502 memdep_count,
inst->pcState());
508 for (
int i = 0;
i < dependInsts.size(); ++
i) {
509 dependInsts[
i] = NULL;
515 "Memory dependency entry deleted. memdep_count=%i %s\n",
516 memdep_count, inst->pcState());
526 if ((*replay_it)->threadNumber == tid &&
527 (*replay_it)->seqNum > squashed_num) {
541 (*squash_it)->seqNum > squashed_num) {
544 (*squash_it)->seqNum);
550 hash_it =
memDepHash.find((*squash_it)->seqNum);
554 (*hash_it).second->squashed =
true;
556 (*hash_it).second = NULL;
560 MemDepEntry::memdep_erase++;
575 " load: %#x, store: %#x\n", violating_load->pcState().instAddr(),
576 store_inst->pcState().instAddr());
579 violating_load->pcState().instAddr());
586 inst->pcState().instAddr(), inst->seqNum);
588 depPred.
issued(inst->pcState().instAddr(), inst->seqNum, inst->isStore());
598 return (*hash_it).second;
605 "to the ready list.\n", woken_inst_entry->inst->seqNum);
607 assert(!woken_inst_entry->squashed);
617 cprintf(
"Instruction list %i size: %i\n",
623 while (inst_list_it !=
instList[tid].end()) {
624 cprintf(
"Instruction:%i\nPC: %s\n[sn:%llu]\n[tid:%i]\nIssued:%i\n"
626 num, (*inst_list_it)->pcState(),
627 (*inst_list_it)->seqNum,
628 (*inst_list_it)->threadNumber,
629 (*inst_list_it)->isIssued(),
630 (*inst_list_it)->isSquashed());
639 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.
void addReadyMemInst(const DynInstPtr &ready_inst)
Adds a ready memory instruction to the ready list.
~MemDepEntry()
Frees any pointers.
MemDepEntry(const DynInstPtr &new_inst)
Constructs a memory dependence entry.
DynInstPtr inst
The instruction being tracked.
Memory dependency unit class.
bool isDrained() const
Determine if we are drained.
void completeInst(const DynInstPtr &inst)
Notifies completion of an instruction.
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.
void squash(InstSeqNum squashed_num, ThreadID tid)
Squashes for a specific thread until the given sequence number.
void clear()
Resets all tables.
void insertStore(Addr store_PC, InstSeqNum store_seq_num, ThreadID tid)
Inserts a store into the store set predictor.
void init(uint64_t clear_period, int SSIT_size, int LFST_size)
Initializes the store set predictor with the given table sizes.
void issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store)
Records this PC/sequence number as issued.
InstSeqNum checkInst(Addr PC)
Checks if the instruction with the given PC is dependent upon any store.
void violation(Addr store_PC, Addr load_PC)
Records a memory ordering violation between the younger load and the older store.
#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
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria 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.
const std::string & name()