40 #include "debug/MemDepUnit.hh"
41 #include "params/BaseO3CPU.hh"
50 int MemDepUnit::MemDepEntry::memdep_count = 0;
51 int MemDepUnit::MemDepEntry::memdep_insert = 0;
52 int 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),
109 "Number of loads inserted to the mem dependence unit."),
111 "Number of stores inserted to the mem dependence unit."),
113 "Number of conflicting loads."),
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
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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()