From 5a49cd94f4c89b07741fe311e6094770d3b19490 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 14 Oct 2021 01:18:57 -0700 Subject: [PATCH] cpu-o3: Mostly use PCStateBase instead of TheISA::PCState. There are a few places where TheISA::PCState is still necessary, specifically when checking if a PC is branching, and also when getting the nextInstAddr. It's likely that checking if a PC is branching will become part of the base PCState interface, but nextInstAddr will likely be removed from the ThreadContext, ExecContext, etc, interfaces, and then removed from the interfaces in the O3 which doesn't seem to use them internally. Change-Id: I499f31d569b9b0c665a745caf612d1e96babf37a Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/52051 Tested-by: kokoro Maintainer: Gabe Black Reviewed-by: Daniel Carvalho --- src/cpu/o3/comm.hh | 6 +- src/cpu/o3/commit.cc | 33 +++++----- src/cpu/o3/commit.hh | 17 +++-- src/cpu/o3/cpu.cc | 2 +- src/cpu/o3/decode.cc | 6 +- src/cpu/o3/dyn_inst.cc | 26 +++++--- src/cpu/o3/dyn_inst.hh | 50 ++++++++++----- src/cpu/o3/fetch.cc | 141 ++++++++++++++++++++--------------------- src/cpu/o3/fetch.hh | 16 ++--- src/cpu/o3/iew.cc | 13 ++-- 10 files changed, 165 insertions(+), 145 deletions(-) diff --git a/src/cpu/o3/comm.hh b/src/cpu/o3/comm.hh index fc108484d3..b2da358d31 100644 --- a/src/cpu/o3/comm.hh +++ b/src/cpu/o3/comm.hh @@ -94,7 +94,7 @@ struct IEWStruct DynInstPtr mispredictInst[MaxThreads]; Addr mispredPC[MaxThreads]; InstSeqNum squashedSeqNum[MaxThreads]; - TheISA::PCState pc[MaxThreads]; + std::unique_ptr pc[MaxThreads]; bool squash[MaxThreads]; bool branchMispredict[MaxThreads]; @@ -114,7 +114,7 @@ struct TimeStruct { struct DecodeComm { - TheISA::PCState nextPC; + std::unique_ptr nextPC; DynInstPtr mispredictInst; DynInstPtr squashInst; InstSeqNum doneSeqNum; @@ -169,7 +169,7 @@ struct TimeStruct /// The pc of the next instruction to execute. This is the next /// instruction for a branch mispredict, but the same instruction for /// order violation and the like - TheISA::PCState pc; // *F + std::unique_ptr pc; // *F /// Provide fetch the instruction that mispredicted, if this /// pointer is not-null a misprediction occured diff --git a/src/cpu/o3/commit.cc b/src/cpu/o3/commit.cc index 421f1e53a7..01ec0c8270 100644 --- a/src/cpu/o3/commit.cc +++ b/src/cpu/o3/commit.cc @@ -120,7 +120,7 @@ Commit::Commit(CPU *_cpu, const O3CPUParams ¶ms) trapSquash[tid] = false; tcSquash[tid] = false; squashAfterInst[tid] = nullptr; - pc[tid].set(0); + pc[tid].reset(params.isa[0]->newPCState()); youngestSeqNum[tid] = 0; lastCommitedSeqNum[tid] = 0; trapInFlight[tid] = false; @@ -340,7 +340,7 @@ Commit::clearStates(ThreadID tid) committedStores[tid] = false; trapSquash[tid] = false; tcSquash[tid] = false; - pc[tid].set(0); + pc[tid].reset(cpu->tcBase(tid)->getIsaPtr()->newPCState()); lastCommitedSeqNum[tid] = 0; squashAfterInst[tid] = NULL; } @@ -382,7 +382,7 @@ Commit::isDrained() const * address mappings. This can happen on for example x86. */ for (ThreadID tid = 0; tid < numThreads; tid++) { - if (pc[tid].microPC() != 0) + if (pc[tid]->microPC() != 0) return false; } @@ -561,7 +561,7 @@ Commit::squashAll(ThreadID tid) toIEW->commitInfo[tid].mispredictInst = NULL; toIEW->commitInfo[tid].squashInst = NULL; - toIEW->commitInfo[tid].pc = pc[tid]; + set(toIEW->commitInfo[tid].pc, pc[tid]); } void @@ -569,7 +569,7 @@ Commit::squashFromTrap(ThreadID tid) { squashAll(tid); - DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", pc[tid]); + DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", *pc[tid]); thread[tid]->trapPending = false; thread[tid]->noSquashFromTC = false; @@ -586,7 +586,7 @@ Commit::squashFromTC(ThreadID tid) { squashAll(tid); - DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", pc[tid]); + DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", *pc[tid]); thread[tid]->noSquashFromTC = false; assert(!thread[tid]->trapPending); @@ -601,7 +601,7 @@ void Commit::squashFromSquashAfter(ThreadID tid) { DPRINTF(Commit, "Squashing after squash after request, " - "restarting at PC %s\n", pc[tid]); + "restarting at PC %s\n", *pc[tid]); squashAll(tid); // Make sure to inform the fetch stage of which instruction caused @@ -843,8 +843,7 @@ Commit::commit() } DPRINTF(Commit, "[tid:%i] Redirecting to PC %#x\n", - tid, - fromIEW->pc[tid].nextInstAddr()); + tid, *fromIEW->pc[tid]); commitStatus[tid] = ROBSquashing; @@ -884,7 +883,7 @@ Commit::commit() ++stats.branchMispredicts; } - toIEW->commitInfo[tid].pc = fromIEW->pc[tid]; + set(toIEW->commitInfo[tid].pc, fromIEW->pc[tid]); } if (commitStatus[tid] == ROBSquashing) { @@ -1014,7 +1013,7 @@ Commit::commitInsts() // Record that the number of ROB entries has changed. changedROBNumEntries[tid] = true; } else { - pc[tid] = head_inst->pcState(); + set(pc[tid], head_inst->pcState()); // Try to commit the head instruction. bool commit_success = commitHead(head_inst, num_committed); @@ -1064,9 +1063,9 @@ Commit::commitInsts() cpu->checker->verify(head_inst); } - cpu->traceFunctions(pc[tid].instAddr()); + cpu->traceFunctions(pc[tid]->instAddr()); - head_inst->staticInst->advancePC(pc[tid]); + head_inst->staticInst->advancePC(*pc[tid]); // Keep track of the last sequence number commited lastCommitedSeqNum[tid] = head_inst->seqNum; @@ -1077,12 +1076,12 @@ Commit::commitInsts() squashAfter(tid, head_inst); if (drainPending) { - if (pc[tid].microPC() == 0 && interrupt == NoFault && + if (pc[tid]->microPC() == 0 && interrupt == NoFault && !thread[tid]->trapPending) { // Last architectually committed instruction. // Squash the pipeline, stall fetch, and use // drainImminent to disable interrupts - DPRINTF(Drain, "Draining: %i:%s\n", tid, pc[tid]); + DPRINTF(Drain, "Draining: %i:%s\n", tid, *pc[tid]); squashAfter(tid, head_inst); cpu->commitDrained(tid); drainImminent = true; @@ -1101,11 +1100,11 @@ Commit::commitInsts() assert(!thread[tid]->noSquashFromTC && !thread[tid]->trapPending); do { - oldpc = pc[tid].instAddr(); + oldpc = pc[tid]->instAddr(); thread[tid]->pcEventQueue.service( oldpc, thread[tid]->getTC()); count++; - } while (oldpc != pc[tid].instAddr()); + } while (oldpc != pc[tid]->instAddr()); if (count > 1) { DPRINTF(Commit, "PC skip function event, stopping commit\n"); diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index bcb7c237a2..8a005e23af 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -306,20 +306,23 @@ class Commit public: /** Reads the PC of a specific thread. */ - TheISA::PCState pcState(ThreadID tid) { return pc[tid]; } + const PCStateBase &pcState(ThreadID tid) { return *pc[tid]; } /** Sets the PC of a specific thread. */ - void pcState(const TheISA::PCState &val, ThreadID tid) - { pc[tid] = val; } + void pcState(const PCStateBase &val, ThreadID tid) { set(pc[tid], val); } /** Returns the PC of a specific thread. */ - Addr instAddr(ThreadID tid) { return pc[tid].instAddr(); } + Addr instAddr(ThreadID tid) { return pc[tid]->instAddr(); } /** Returns the next PC of a specific thread. */ - Addr nextInstAddr(ThreadID tid) { return pc[tid].nextInstAddr(); } + Addr + nextInstAddr(ThreadID tid) + { + return pc[tid]->as().nextInstAddr(); + } /** Reads the micro PC of a specific thread. */ - Addr microPC(ThreadID tid) { return pc[tid].microPC(); } + Addr microPC(ThreadID tid) { return pc[tid]->microPC(); } private: /** Time buffer interface. */ @@ -431,7 +434,7 @@ class Commit /** The commit PC state of each thread. Refers to the instruction that * is currently being processed/committed. */ - TheISA::PCState pc[MaxThreads]; + std::unique_ptr pc[MaxThreads]; /** The sequence number of the youngest valid instruction in the ROB. */ InstSeqNum youngestSeqNum[MaxThreads]; diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index a155d789c5..05d3a51966 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -1310,7 +1310,7 @@ CPU::setArchCCReg(int reg_idx, RegVal val, ThreadID tid) TheISA::PCState CPU::pcState(ThreadID tid) { - return commit.pcState(tid); + return commit.pcState(tid).as(); } void diff --git a/src/cpu/o3/decode.cc b/src/cpu/o3/decode.cc index 5a275738c9..d10e19a2a3 100644 --- a/src/cpu/o3/decode.cc +++ b/src/cpu/o3/decode.cc @@ -715,13 +715,13 @@ Decode::decodeInsts(ThreadID tid) { ++stats.branchResolved; - if (*inst->branchTarget() != inst->readPredTarg()) { + std::unique_ptr target = inst->branchTarget(); + if (*target != inst->readPredTarg()) { ++stats.branchMispred; // Might want to set some sort of boolean and just do // a check at the end squash(inst, inst->threadNumber); - std::unique_ptr target = inst->branchTarget(); DPRINTF(Decode, "[tid:%i] [sn:%llu] " @@ -729,7 +729,7 @@ Decode::decodeInsts(ThreadID tid) PredPC: %s\n", tid, inst->seqNum, inst->readPredTarg(), *target); //The micro pc after an instruction level branch should be 0 - inst->setPredTarg(target->as()); + inst->setPredTarg(*target); break; } } diff --git a/src/cpu/o3/dyn_inst.cc b/src/cpu/o3/dyn_inst.cc index 37db1ed06f..8284c9a113 100644 --- a/src/cpu/o3/dyn_inst.cc +++ b/src/cpu/o3/dyn_inst.cc @@ -53,11 +53,10 @@ namespace o3 { DynInst::DynInst(const StaticInstPtr &static_inst, - const StaticInstPtr &_macroop, TheISA::PCState _pc, - TheISA::PCState pred_pc, InstSeqNum seq_num, CPU *_cpu) - : seqNum(seq_num), staticInst(static_inst), cpu(_cpu), pc(_pc), + const StaticInstPtr &_macroop, InstSeqNum seq_num, CPU *_cpu) + : seqNum(seq_num), staticInst(static_inst), cpu(_cpu), regs(staticInst->numSrcRegs(), staticInst->numDestRegs()), - predPC(pred_pc), macroop(_macroop) + macroop(_macroop) { regs.init(); @@ -90,9 +89,18 @@ DynInst::DynInst(const StaticInstPtr &static_inst, } +DynInst::DynInst(const StaticInstPtr &static_inst, + const StaticInstPtr &_macroop, const PCStateBase &_pc, + const PCStateBase &pred_pc, InstSeqNum seq_num, CPU *_cpu) + : DynInst(static_inst, _macroop, seq_num, _cpu) +{ + set(pc, _pc); + set(predPC, pred_pc); +} + DynInst::DynInst(const StaticInstPtr &_staticInst, const StaticInstPtr &_macroop) - : DynInst(_staticInst, _macroop, {}, {}, 0, nullptr) + : DynInst(_staticInst, _macroop, 0, nullptr) {} DynInst::~DynInst() @@ -166,8 +174,8 @@ DynInst::dumpSNList() void DynInst::dump() { - cprintf("T%d : %#08d `", threadNumber, pc.instAddr()); - std::cout << staticInst->disassemble(pc.instAddr()); + cprintf("T%d : %#08d `", threadNumber, pc->instAddr()); + std::cout << staticInst->disassemble(pc->instAddr()); cprintf("'\n"); } @@ -175,8 +183,8 @@ void DynInst::dump(std::string &outstring) { std::ostringstream s; - s << "T" << threadNumber << " : 0x" << pc.instAddr() << " " - << staticInst->disassemble(pc.instAddr()); + s << "T" << threadNumber << " : 0x" << pc->instAddr() << " " + << staticInst->disassemble(pc->instAddr()); outstring = s.str(); } diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index 38815b1d42..c7e99a4f12 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -75,13 +75,17 @@ namespace o3 class DynInst : public ExecContext, public RefCounted { + private: + DynInst(const StaticInstPtr &staticInst, const StaticInstPtr ¯oop, + InstSeqNum seq_num, CPU *cpu); + public: // The list of instructions iterator type. typedef typename std::list::iterator ListIt; /** BaseDynInst constructor given a binary instruction. */ DynInst(const StaticInstPtr &staticInst, const StaticInstPtr - ¯oop, TheISA::PCState pc, TheISA::PCState predPC, + ¯oop, const PCStateBase &pc, const PCStateBase &pred_pc, InstSeqNum seq_num, CPU *cpu); /** BaseDynInst constructor given a static inst pointer. */ @@ -182,7 +186,7 @@ class DynInst : public ExecContext, public RefCounted std::queue instResult; /** PC state for this instruction. */ - TheISA::PCState pc; + std::unique_ptr pc; /** Values to be written to the destination misc. registers. */ std::vector _destMiscRegVal; @@ -361,7 +365,7 @@ class DynInst : public ExecContext, public RefCounted ////////////////////// Branch Data /////////////// /** Predicted PC state after this instruction. */ - TheISA::PCState predPC; + std::unique_ptr predPC; /** The Macroop if one exists */ const StaticInstPtr macroop; @@ -551,18 +555,22 @@ class DynInst : public ExecContext, public RefCounted bool doneTargCalc() { return false; } /** Set the predicted target of this current instruction. */ - void setPredTarg(const TheISA::PCState &_predPC) { predPC = _predPC; } + void setPredTarg(const PCStateBase &pred_pc) { set(predPC, pred_pc); } - const TheISA::PCState &readPredTarg() { return predPC; } + const PCStateBase &readPredTarg() { return *predPC; } /** Returns the predicted PC immediately after the branch. */ - Addr predInstAddr() { return predPC.instAddr(); } + Addr predInstAddr() { return predPC->instAddr(); } /** Returns the predicted PC two instructions after the branch */ - Addr predNextInstAddr() { return predPC.nextInstAddr(); } + Addr + predNextInstAddr() + { + return predPC->as().nextInstAddr(); + } /** Returns the predicted micro PC after the branch */ - Addr predMicroPC() { return predPC.microPC(); } + Addr predMicroPC() { return predPC->microPC(); } /** Returns whether the instruction was predicted taken or not. */ bool readPredTaken() { return instFlags[PredTaken]; } @@ -577,9 +585,9 @@ class DynInst : public ExecContext, public RefCounted bool mispredicted() { - TheISA::PCState tempPC = pc; - staticInst->advancePC(tempPC); - return !(tempPC == predPC); + std::unique_ptr next_pc(pc->clone()); + staticInst->advancePC(*next_pc); + return *next_pc != *predPC; } // @@ -720,7 +728,7 @@ class DynInst : public ExecContext, public RefCounted std::unique_ptr branchTarget() const { - return staticInst->branchTarget(pc); + return staticInst->branchTarget(*pc); } /** Returns the number of source registers. */ @@ -941,19 +949,27 @@ class DynInst : public ExecContext, public RefCounted } /** Read the PC state of this instruction. */ - TheISA::PCState pcState() const override { return pc; } + TheISA::PCState + pcState() const override + { + return pc->as(); + } /** Set the PC state of this instruction. */ - void pcState(const TheISA::PCState &val) override { pc = val; } + void pcState(const TheISA::PCState &val) override { set(pc, val); } /** Read the PC of this instruction. */ - Addr instAddr() const { return pc.instAddr(); } + Addr instAddr() const { return pc->instAddr(); } /** Read the PC of the next instruction. */ - Addr nextInstAddr() const { return pc.nextInstAddr(); } + Addr + nextInstAddr() const + { + return pc->as().nextInstAddr(); + } /**Read the micro PC of this instruction. */ - Addr microPC() const { return pc.microPC(); } + Addr microPC() const { return pc->microPC(); } bool readPredicate() const override { return instFlags[Predicate]; } diff --git a/src/cpu/o3/fetch.cc b/src/cpu/o3/fetch.cc index cfc3a83e55..b87af346b4 100644 --- a/src/cpu/o3/fetch.cc +++ b/src/cpu/o3/fetch.cc @@ -120,7 +120,7 @@ Fetch::Fetch(CPU *_cpu, const O3CPUParams ¶ms) for (int i = 0; i < MaxThreads; i++) { fetchStatus[i] = Idle; decoder[i] = nullptr; - pc[i].set(0); + pc[i].reset(params.isa[0]->newPCState()); fetchOffset[i] = 0; macroop[i] = nullptr; delayedCommit[i] = false; @@ -299,7 +299,7 @@ void Fetch::clearStates(ThreadID tid) { fetchStatus[tid] = Running; - pc[tid] = cpu->pcState(tid); + set(pc[tid], cpu->pcState(tid)); fetchOffset[tid] = 0; macroop[tid] = NULL; delayedCommit[tid] = false; @@ -326,7 +326,7 @@ Fetch::resetStage() // Setup PC and nextPC with initial state. for (ThreadID tid = 0; tid < numThreads; ++tid) { fetchStatus[tid] = Running; - pc[tid] = cpu->pcState(tid); + set(pc[tid], cpu->pcState(tid)); fetchOffset[tid] = 0; macroop[tid] = NULL; @@ -508,7 +508,7 @@ Fetch::deactivateThread(ThreadID tid) } bool -Fetch::lookupAndUpdateNextPC(const DynInstPtr &inst, TheISA::PCState &nextPC) +Fetch::lookupAndUpdateNextPC(const DynInstPtr &inst, PCStateBase &next_pc) { // Do branch prediction check here. // A bit of a misnomer...next_PC is actually the current PC until @@ -516,20 +516,20 @@ Fetch::lookupAndUpdateNextPC(const DynInstPtr &inst, TheISA::PCState &nextPC) bool predict_taken; if (!inst->isControl()) { - inst->staticInst->advancePC(nextPC); - inst->setPredTarg(nextPC); + inst->staticInst->advancePC(next_pc); + inst->setPredTarg(next_pc); inst->setPredTaken(false); return false; } ThreadID tid = inst->threadNumber; predict_taken = branchPred->predict(inst->staticInst, inst->seqNum, - nextPC, tid); + next_pc.as(), tid); if (predict_taken) { DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x " "predicted to be taken to %s\n", - tid, inst->seqNum, inst->pcState().instAddr(), nextPC); + tid, inst->seqNum, inst->pcState().instAddr(), next_pc); } else { DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x " "predicted to be not taken\n", @@ -538,8 +538,8 @@ Fetch::lookupAndUpdateNextPC(const DynInstPtr &inst, TheISA::PCState &nextPC) DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x " "predicted to go to %s\n", - tid, inst->seqNum, inst->pcState().instAddr(), nextPC); - inst->setPredTarg(nextPC); + tid, inst->seqNum, inst->pcState().instAddr(), next_pc); + inst->setPredTarg(next_pc); inst->setPredTaken(predict_taken); ++fetchStats.branches; @@ -683,15 +683,15 @@ Fetch::finishTranslation(const Fault &fault, const RequestPtr &mem_req) // Send the fault to commit. This thread will not do anything // until commit handles the fault. The only other way it can // wake up is if a squash comes along and changes the PC. - TheISA::PCState fetchPC = pc[tid]; + const PCStateBase &fetch_pc = *pc[tid]; DPRINTF(Fetch, "[tid:%i] Translation faulted, building noop.\n", tid); // We will use a nop in ordier to carry the fault. DynInstPtr instruction = buildInst(tid, nopStaticInstPtr, nullptr, - fetchPC, fetchPC, false); + fetch_pc, fetch_pc, false); instruction->setNotAnInst(); - instruction->setPredTarg(fetchPC); + instruction->setPredTarg(fetch_pc); instruction->fault = fault; wroteToTimeBuffer = true; @@ -702,21 +702,21 @@ Fetch::finishTranslation(const Fault &fault, const RequestPtr &mem_req) DPRINTF(Fetch, "[tid:%i] Blocked, need to handle the trap.\n", tid); DPRINTF(Fetch, "[tid:%i] fault (%s) detected @ PC %s.\n", - tid, fault->name(), pc[tid]); + tid, fault->name(), *pc[tid]); } _status = updateFetchStatus(); } void -Fetch::doSquash(const TheISA::PCState &newPC, const DynInstPtr squashInst, +Fetch::doSquash(const PCStateBase &new_pc, const DynInstPtr squashInst, ThreadID tid) { DPRINTF(Fetch, "[tid:%i] Squashing, setting PC to: %s.\n", - tid, newPC); + tid, new_pc); - pc[tid] = newPC; + set(pc[tid], new_pc); fetchOffset[tid] = 0; - if (squashInst && squashInst->pcState().instAddr() == newPC.instAddr()) + if (squashInst && squashInst->pcState().instAddr() == new_pc.instAddr()) macroop[tid] = squashInst->macroop; else macroop[tid] = NULL; @@ -759,12 +759,12 @@ Fetch::doSquash(const TheISA::PCState &newPC, const DynInstPtr squashInst, } void -Fetch::squashFromDecode(const TheISA::PCState &newPC, - const DynInstPtr squashInst, const InstSeqNum seq_num, ThreadID tid) +Fetch::squashFromDecode(const PCStateBase &new_pc, const DynInstPtr squashInst, + const InstSeqNum seq_num, ThreadID tid) { DPRINTF(Fetch, "[tid:%i] Squashing from decode.\n", tid); - doSquash(newPC, squashInst, tid); + doSquash(new_pc, squashInst, tid); // Tell the CPU to remove any instructions that are in flight between // fetch and decode. @@ -825,12 +825,12 @@ Fetch::updateFetchStatus() } void -Fetch::squash(const TheISA::PCState &newPC, const InstSeqNum seq_num, +Fetch::squash(const PCStateBase &new_pc, const InstSeqNum seq_num, DynInstPtr squashInst, ThreadID tid) { DPRINTF(Fetch, "[tid:%i] Squash from commit.\n", tid); - doSquash(newPC, squashInst, tid); + doSquash(new_pc, squashInst, tid); // Tell the CPU to remove any instructions that are not in the ROB. cpu->removeInstsNotInROB(tid); @@ -958,7 +958,7 @@ Fetch::checkSignalsAndUpdate(ThreadID tid) DPRINTF(Fetch, "[tid:%i] Squashing instructions due to squash " "from commit.\n",tid); // In any case, squash. - squash(fromCommit->commitInfo[tid].pc, + squash(*fromCommit->commitInfo[tid].pc, fromCommit->commitInfo[tid].doneSeqNum, fromCommit->commitInfo[tid].squashInst, tid); @@ -968,9 +968,8 @@ Fetch::checkSignalsAndUpdate(ThreadID tid) if (fromCommit->commitInfo[tid].mispredictInst && fromCommit->commitInfo[tid].mispredictInst->isControl()) { branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum, - fromCommit->commitInfo[tid].pc, - fromCommit->commitInfo[tid].branchTaken, - tid); + fromCommit->commitInfo[tid].pc->as(), + fromCommit->commitInfo[tid].branchTaken, tid); } else { branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum, tid); @@ -991,9 +990,8 @@ Fetch::checkSignalsAndUpdate(ThreadID tid) // Update the branch predictor. if (fromDecode->decodeInfo[tid].branchMispredict) { branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum, - fromDecode->decodeInfo[tid].nextPC, - fromDecode->decodeInfo[tid].branchTaken, - tid); + fromDecode->decodeInfo[tid].nextPC->as(), + fromDecode->decodeInfo[tid].branchTaken, tid); } else { branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum, tid); @@ -1002,9 +1000,9 @@ Fetch::checkSignalsAndUpdate(ThreadID tid) if (fetchStatus[tid] != Squashing) { DPRINTF(Fetch, "Squashing from decode with PC = %s\n", - fromDecode->decodeInfo[tid].nextPC); + *fromDecode->decodeInfo[tid].nextPC); // Squash unless we're already squashing - squashFromDecode(fromDecode->decodeInfo[tid].nextPC, + squashFromDecode(*fromDecode->decodeInfo[tid].nextPC, fromDecode->decodeInfo[tid].squashInst, fromDecode->decodeInfo[tid].doneSeqNum, tid); @@ -1044,32 +1042,30 @@ Fetch::checkSignalsAndUpdate(ThreadID tid) DynInstPtr Fetch::buildInst(ThreadID tid, StaticInstPtr staticInst, - StaticInstPtr curMacroop, TheISA::PCState thisPC, - TheISA::PCState nextPC, bool trace) + StaticInstPtr curMacroop, const PCStateBase &this_pc, + const PCStateBase &next_pc, bool trace) { // Get a sequence number. InstSeqNum seq = cpu->getAndIncrementInstSeq(); // Create a new DynInst from the instruction fetched. DynInstPtr instruction = - new DynInst(staticInst, curMacroop, thisPC, nextPC, seq, cpu); + new DynInst(staticInst, curMacroop, this_pc, next_pc, seq, cpu); instruction->setTid(tid); instruction->setThreadState(cpu->thread[tid]); - DPRINTF(Fetch, "[tid:%i] Instruction PC %#x (%d) created " - "[sn:%lli].\n", tid, thisPC.instAddr(), - thisPC.microPC(), seq); + DPRINTF(Fetch, "[tid:%i] Instruction PC %s created [sn:%lli].\n", + tid, this_pc, seq); DPRINTF(Fetch, "[tid:%i] Instruction is: %s\n", tid, - instruction->staticInst-> - disassemble(thisPC.instAddr())); + instruction->staticInst->disassemble(this_pc.instAddr())); #if TRACING_ON if (trace) { instruction->traceData = cpu->getTracer()->getInstRecord(curTick(), cpu->tcBase(tid), - instruction->staticInst, thisPC, curMacroop); + instruction->staticInst, this_pc, curMacroop); } #else instruction->traceData = NULL; @@ -1117,12 +1113,12 @@ Fetch::fetch(bool &status_change) DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid); // The current PC. - TheISA::PCState thisPC = pc[tid]; + PCStateBase &this_pc = *pc[tid]; Addr pcOffset = fetchOffset[tid]; - Addr fetchAddr = (thisPC.instAddr() + pcOffset) & decoder[tid]->pcMask(); + Addr fetchAddr = (this_pc.instAddr() + pcOffset) & decoder[tid]->pcMask(); - bool inRom = isRomMicroPC(thisPC.microPC()); + bool inRom = isRomMicroPC(this_pc.microPC()); // If returning from the delay of a cache miss, then update the status // to running, otherwise do the cache access. Possibly move this up @@ -1143,9 +1139,9 @@ Fetch::fetch(bool &status_change) fetchBufferBlockPC == fetchBufferPC[tid]) && !inRom && !macroop[tid]) { DPRINTF(Fetch, "[tid:%i] Attempting to translate and read " - "instruction, starting at PC %s.\n", tid, thisPC); + "instruction, starting at PC %s.\n", tid, this_pc); - fetchCacheLine(fetchAddr, tid, thisPC.instAddr()); + fetchCacheLine(fetchAddr, tid, this_pc.instAddr()); if (fetchStatus[tid] == IcacheWaitResponse) ++fetchStats.icacheStallCycles; @@ -1154,7 +1150,8 @@ Fetch::fetch(bool &status_change) else ++fetchStats.miscStallCycles; return; - } else if (checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid]) { + } else if (checkInterrupt(this_pc.instAddr()) && + !delayedCommit[tid]) { // Stall CPU if an interrupt is posted and we're not issuing // an delayed commit micro-op currently (delayed commit // instructions are not interruptable by interrupts, only faults) @@ -1174,7 +1171,7 @@ Fetch::fetch(bool &status_change) ++fetchStats.cycles; - TheISA::PCState nextPC = thisPC; + std::unique_ptr next_pc(this_pc.clone()); StaticInstPtr staticInst = NULL; StaticInstPtr curMacroop = macroop[tid]; @@ -1208,7 +1205,7 @@ Fetch::fetch(bool &status_change) // StaticInst from the rom, the current macroop, or what's already // in the decoder. bool needMem = !inRom && !curMacroop && !dec_ptr->instReady(); - fetchAddr = (thisPC.instAddr() + pcOffset) & pc_mask; + fetchAddr = (this_pc.instAddr() + pcOffset) & pc_mask; Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr); if (needMem) { @@ -1226,7 +1223,7 @@ Fetch::fetch(bool &status_change) memcpy(dec_ptr->moreBytesPtr(), fetchBuffer[tid] + blkOffset * instSize, instSize); - decoder[tid]->moreBytes(thisPC, fetchAddr); + decoder[tid]->moreBytes(this_pc.as(), fetchAddr); if (dec_ptr->needMoreBytes()) { blkOffset++; @@ -1240,7 +1237,8 @@ Fetch::fetch(bool &status_change) do { if (!(curMacroop || inRom)) { if (dec_ptr->instReady()) { - staticInst = dec_ptr->decode(thisPC); + staticInst = dec_ptr->decode( + this_pc.as()); // Increment stat of fetched instructions. ++fetchStats.insts; @@ -1263,15 +1261,15 @@ Fetch::fetch(bool &status_change) if (curMacroop || inRom) { if (inRom) { staticInst = dec_ptr->fetchRomMicroop( - thisPC.microPC(), curMacroop); + this_pc.microPC(), curMacroop); } else { - staticInst = curMacroop->fetchMicroop(thisPC.microPC()); + staticInst = curMacroop->fetchMicroop(this_pc.microPC()); } newMacro |= staticInst->isLastMicroop(); } - DynInstPtr instruction = - buildInst(tid, staticInst, curMacroop, thisPC, nextPC, true); + DynInstPtr instruction = buildInst( + tid, staticInst, curMacroop, this_pc, *next_pc, true); ppFetch->notify(instruction); numInst++; @@ -1282,25 +1280,24 @@ Fetch::fetch(bool &status_change) } #endif - nextPC = thisPC; + set(next_pc, this_pc); // If we're branching after this instruction, quit fetching // from the same block. - predictedBranch |= thisPC.branching(); - predictedBranch |= - lookupAndUpdateNextPC(instruction, nextPC); + predictedBranch |= this_pc.as().branching(); + predictedBranch |= lookupAndUpdateNextPC(instruction, *next_pc); if (predictedBranch) { - DPRINTF(Fetch, "Branch detected with PC = %s\n", thisPC); + DPRINTF(Fetch, "Branch detected with PC = %s\n", this_pc); } - newMacro |= thisPC.instAddr() != nextPC.instAddr(); + newMacro |= this_pc.instAddr() != next_pc->instAddr(); // Move to the next instruction, unless we have a branch. - thisPC = nextPC; - inRom = isRomMicroPC(thisPC.microPC()); + set(this_pc, *next_pc); + inRom = isRomMicroPC(this_pc.microPC()); if (newMacro) { - fetchAddr = thisPC.instAddr() & pc_mask; + fetchAddr = this_pc.instAddr() & pc_mask; blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize; pcOffset = 0; curMacroop = NULL; @@ -1320,7 +1317,7 @@ Fetch::fetch(bool &status_change) // Re-evaluate whether the next instruction to fetch is in micro-op ROM // or not. - inRom = isRomMicroPC(thisPC.microPC()); + inRom = isRomMicroPC(this_pc.microPC()); } if (predictedBranch) { @@ -1341,11 +1338,9 @@ Fetch::fetch(bool &status_change) wroteToTimeBuffer = true; } - pc[tid] = thisPC; - // pipeline a fetch if we're crossing a fetch buffer boundary and not in // a state that would preclude fetching - fetchAddr = (thisPC.instAddr() + pcOffset) & pc_mask; + fetchAddr = (this_pc.instAddr() + pcOffset) & pc_mask; Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr); issuePipelinedIfetch[tid] = fetchBufferBlockPC != fetchBufferPC[tid] && fetchStatus[tid] != IcacheWaitResponse && @@ -1535,14 +1530,14 @@ Fetch::pipelineIcacheAccesses(ThreadID tid) } // The next PC to access. - TheISA::PCState thisPC = pc[tid]; + const PCStateBase &this_pc = *pc[tid]; - if (isRomMicroPC(thisPC.microPC())) { + if (isRomMicroPC(this_pc.microPC())) { return; } Addr pcOffset = fetchOffset[tid]; - Addr fetchAddr = (thisPC.instAddr() + pcOffset) & decoder[tid]->pcMask(); + Addr fetchAddr = (this_pc.instAddr() + pcOffset) & decoder[tid]->pcMask(); // Align the fetch PC so its at the start of a fetch buffer segment. Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr); @@ -1550,9 +1545,9 @@ Fetch::pipelineIcacheAccesses(ThreadID tid) // Unless buffer already got the block, fetch it from icache. if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])) { DPRINTF(Fetch, "[tid:%i] Issuing a pipelined I-cache access, " - "starting at PC %s.\n", tid, thisPC); + "starting at PC %s.\n", tid, this_pc); - fetchCacheLine(fetchAddr, tid, thisPC.instAddr()); + fetchCacheLine(fetchAddr, tid, this_pc.instAddr()); } } diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 5bfb01a277..2d903b2c30 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -284,7 +284,7 @@ class Fetch * @param next_NPC Used for ISAs which use delay slots. * @return Whether or not a branch was predicted as taken. */ - bool lookupAndUpdateNextPC(const DynInstPtr &inst, TheISA::PCState &pc); + bool lookupAndUpdateNextPC(const DynInstPtr &inst, PCStateBase &pc); /** * Fetches the cache line that contains the fetch PC. Returns any @@ -306,14 +306,14 @@ class Fetch bool checkInterrupt(Addr pc) { return interruptPending; } /** Squashes a specific thread and resets the PC. */ - void doSquash(const TheISA::PCState &newPC, - const DynInstPtr squashInst, ThreadID tid); + void doSquash(const PCStateBase &new_pc, const DynInstPtr squashInst, + ThreadID tid); /** Squashes a specific thread and resets the PC. Also tells the CPU to * remove any instructions between fetch and decode * that should be sqaushed. */ - void squashFromDecode(const TheISA::PCState &newPC, + void squashFromDecode(const PCStateBase &new_pc, const DynInstPtr squashInst, const InstSeqNum seq_num, ThreadID tid); @@ -329,7 +329,7 @@ class Fetch * remove any instructions that are not in the ROB. The source of this * squash should be the commit stage. */ - void squash(const TheISA::PCState &newPC, const InstSeqNum seq_num, + void squash(const PCStateBase &new_pc, const InstSeqNum seq_num, DynInstPtr squashInst, ThreadID tid); /** Ticks the fetch stage, processing all inputs signals and fetching @@ -362,8 +362,8 @@ class Fetch private: DynInstPtr buildInst(ThreadID tid, StaticInstPtr staticInst, - StaticInstPtr curMacroop, TheISA::PCState thisPC, - TheISA::PCState nextPC, bool trace); + StaticInstPtr curMacroop, const PCStateBase &this_pc, + const PCStateBase &next_pc, bool trace); /** Returns the appropriate thread to fetch, given the fetch policy. */ ThreadID getFetchingThread(); @@ -413,7 +413,7 @@ class Fetch /** BPredUnit. */ branch_prediction::BPredUnit *branchPred; - TheISA::PCState pc[MaxThreads]; + std::unique_ptr pc[MaxThreads]; Addr fetchOffset[MaxThreads]; diff --git a/src/cpu/o3/iew.cc b/src/cpu/o3/iew.cc index d899e8b128..79e0783f65 100644 --- a/src/cpu/o3/iew.cc +++ b/src/cpu/o3/iew.cc @@ -463,10 +463,9 @@ IEW::squashDueToBranch(const DynInstPtr& inst, ThreadID tid) toCommit->squashedSeqNum[tid] = inst->seqNum; toCommit->branchTaken[tid] = inst->pcState().branching(); - TheISA::PCState pc = inst->pcState(); - inst->staticInst->advancePC(pc); + set(toCommit->pc[tid], inst->pcState()); + inst->staticInst->advancePC(*toCommit->pc[tid]); - toCommit->pc[tid] = pc; toCommit->mispredictInst[tid] = inst; toCommit->includeSquashInst[tid] = false; @@ -491,7 +490,7 @@ IEW::squashDueToMemOrder(const DynInstPtr& inst, ThreadID tid) toCommit->squash[tid] = true; toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->pc[tid] = inst->pcState(); + set(toCommit->pc[tid], inst->pcState()); toCommit->mispredictInst[tid] = NULL; // Must include the memory violator in the squash. @@ -1301,13 +1300,13 @@ IEW::executeInsts() DPRINTF(IEW, "[tid:%i] [sn:%llu] Execute: " "Branch mispredict detected.\n", - tid,inst->seqNum); + tid, inst->seqNum); DPRINTF(IEW, "[tid:%i] [sn:%llu] " "Predicted target was PC: %s\n", - tid,inst->seqNum,inst->readPredTarg()); + tid, inst->seqNum, inst->readPredTarg()); DPRINTF(IEW, "[tid:%i] [sn:%llu] Execute: " "Redirecting fetch to PC: %s\n", - tid,inst->seqNum,inst->pcState()); + tid, inst->seqNum, inst->pcState()); // If incorrect, then signal the ROB that it must be squashed. squashDueToBranch(inst, tid);