inorder: use setupSquash for misspeculation
implement a clean interface to handle branch misprediction and eventually all pipeline flushing
This commit is contained in:
@@ -1272,6 +1272,24 @@ InOrderCPU::addInst(DynInstPtr inst)
|
||||
return --(instList[tid].end());
|
||||
}
|
||||
|
||||
InOrderCPU::ListIt
|
||||
InOrderCPU::findInst(InstSeqNum seq_num, ThreadID tid)
|
||||
{
|
||||
ListIt it = instList[tid].begin();
|
||||
ListIt end = instList[tid].end();
|
||||
|
||||
while (it != end) {
|
||||
if ((*it)->seqNum == seq_num)
|
||||
return it;
|
||||
else if ((*it)->seqNum > seq_num)
|
||||
break;
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
return instList[tid].end();
|
||||
}
|
||||
|
||||
void
|
||||
InOrderCPU::updateContextSwitchStats()
|
||||
{
|
||||
|
||||
@@ -581,6 +581,9 @@ class InOrderCPU : public BaseCPU
|
||||
*/
|
||||
ListIt addInst(DynInstPtr inst);
|
||||
|
||||
/** Find instruction on instruction list */
|
||||
ListIt findInst(InstSeqNum seq_num, ThreadID tid);
|
||||
|
||||
/** Function to tell the CPU that an instruction has completed. */
|
||||
void instDone(DynInstPtr inst, ThreadID tid);
|
||||
|
||||
|
||||
@@ -315,6 +315,28 @@ InOrderDynInst::syscall(int64_t callnum)
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
InOrderDynInst::setSquashInfo(unsigned stage_num)
|
||||
{
|
||||
squashingStage = stage_num;
|
||||
bdelaySeqNum = seqNum;
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (isControl()) {
|
||||
TheISA::PCState nextPC = pc;
|
||||
TheISA::advancePC(nextPC, staticInst);
|
||||
|
||||
// Check to see if we should squash after the
|
||||
// branch or after a branch delay slot.
|
||||
if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
|
||||
bdelaySeqNum = seqNum + 1;
|
||||
else
|
||||
bdelaySeqNum = seqNum;
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
InOrderDynInst::releaseReq(ResourceRequest* req)
|
||||
{
|
||||
|
||||
@@ -576,6 +576,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted
|
||||
|
||||
bool procDelaySlotOnMispred;
|
||||
|
||||
void setSquashInfo(unsigned stage_num);
|
||||
|
||||
////////////////////////////////////////////
|
||||
//
|
||||
// MEMORY ACCESS
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "base/str.hh"
|
||||
#include "cpu/inorder/cpu.hh"
|
||||
#include "cpu/inorder/resource.hh"
|
||||
#include "cpu/inorder/resource_pool.hh"
|
||||
#include "debug/RefCount.hh"
|
||||
#include "debug/ResReqCount.hh"
|
||||
#include "debug/Resource.hh"
|
||||
@@ -286,6 +287,18 @@ Resource::deactivateThread(ThreadID tid)
|
||||
squash(dummy_inst, 0, 0, tid);
|
||||
}
|
||||
|
||||
void
|
||||
Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
|
||||
{
|
||||
assert(inst->isControl() && "Function Assumes Squash From A Branch");
|
||||
|
||||
// Squash In Pipeline Stage
|
||||
cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
|
||||
|
||||
// Schedule Squash Through-out Resource Pool
|
||||
cpu->resPool->scheduleEvent(
|
||||
(InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
|
||||
}
|
||||
void
|
||||
Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
|
||||
ThreadID tid)
|
||||
|
||||
@@ -154,10 +154,14 @@ class Resource {
|
||||
virtual Fault doCacheAccess(DynInstPtr inst, uint64_t *res=NULL)
|
||||
{ panic("doCacheAccess undefined for %s", name()); return NoFault; }
|
||||
|
||||
/** Setup Squash to be sent out to pipeline and resource pool */
|
||||
void setupSquash(DynInstPtr inst, int stage_num, ThreadID tid);
|
||||
|
||||
/** Squash All Requests After This Seq Num */
|
||||
virtual void squash(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
/** Squash Requests Due to a Memory Stall (By Default, same as "squash" */
|
||||
virtual void squashDueToMemStall(DynInstPtr inst, int stage_num,
|
||||
InstSeqNum squash_seq_num, ThreadID tid);
|
||||
|
||||
|
||||
@@ -148,19 +148,15 @@ void
|
||||
BranchPredictor::squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid, inst->seqNum);
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
// We need to squash the actual branch , NOT the delay slot
|
||||
// in the branch predictor
|
||||
//squash_seq_num = squash_seq_num - 1;
|
||||
#endif
|
||||
InstSeqNum bpred_squash_num = inst->seqNum;
|
||||
DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid,
|
||||
bpred_squash_num);
|
||||
|
||||
if (squash_stage >= ThePipeline::BackEndStartStage) {
|
||||
bool taken = inst->predTaken();
|
||||
branchPred.squash(squash_seq_num, inst->readPredTarg(), taken, tid);
|
||||
branchPred.squash(bpred_squash_num, inst->readPredTarg(), taken, tid);
|
||||
} else {
|
||||
branchPred.squash(squash_seq_num, tid);
|
||||
branchPred.squash(bpred_squash_num, tid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,87 +143,30 @@ ExecutionUnit::execute(int slot_num)
|
||||
inst->setExecuted();
|
||||
|
||||
if (fault == NoFault) {
|
||||
// If branch is mispredicted, then signal squash
|
||||
// throughout all stages behind the pipeline stage
|
||||
// that got squashed.
|
||||
if (inst->mispredicted()) {
|
||||
int stage_num = exec_req->getStageNum();
|
||||
assert(inst->isControl());
|
||||
|
||||
// Set up Squash Generated By this Misprediction
|
||||
unsigned stage_num = exec_req->getStageNum();
|
||||
ThreadID tid = inst->readTid();
|
||||
// If it's a branch ...
|
||||
if (inst->isDirectCtrl()) {
|
||||
assert(!inst->isIndirectCtrl());
|
||||
TheISA::PCState pc = inst->pcState();
|
||||
TheISA::advancePC(pc, inst->staticInst);
|
||||
inst->setPredTarg(pc);
|
||||
inst->setSquashInfo(stage_num);
|
||||
|
||||
TheISA::PCState pc = inst->pcState();
|
||||
TheISA::advancePC(pc, inst->staticInst);
|
||||
inst->setPredTarg(pc);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
if (inst->predTaken() && inst->isCondDelaySlot()) {
|
||||
assert(0 && "Not Handling Conditional Delay Slots (1)");
|
||||
inst->bdelaySeqNum = seq_num;
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: Conditional"
|
||||
" branch inst [sn:%i] PC %s mis"
|
||||
"predicted as taken.\n", tid,
|
||||
seq_num, inst->pcState());
|
||||
} else if (!inst->predTaken() && inst->isCondDelaySlot()) {
|
||||
assert(0 && "Not Handling Conditional Delay Slots (2)");
|
||||
inst->bdelaySeqNum = seq_num;
|
||||
inst->procDelaySlotOnMispred = true;
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: Conditional"
|
||||
" branch inst [sn:%i] PC %s mis"
|
||||
"predicted as not taken.\n", tid,
|
||||
seq_num, inst->pcState());
|
||||
} else {
|
||||
inst->bdelaySeqNum = seq_num;
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: "
|
||||
"Misprediction detected at "
|
||||
"[sn:%i] PC %s,\n\t squashing after "
|
||||
"delay slot instruction [sn:%i].\n",
|
||||
tid, seq_num, inst->pcState(),
|
||||
inst->bdelaySeqNum);
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
|
||||
" misprediction at %s\n",
|
||||
tid, inst->pcState());
|
||||
}
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i] Redirecting "
|
||||
"fetch to %s.\n", tid,
|
||||
inst->readPredTarg());
|
||||
|
||||
} else if (inst->isIndirectCtrl()){
|
||||
TheISA::PCState pc = inst->pcState();
|
||||
TheISA::advancePC(pc, inst->staticInst);
|
||||
inst->seqNum = seq_num;
|
||||
inst->setPredTarg(pc);
|
||||
|
||||
inst->bdelaySeqNum = seq_num;
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i] Redirecting"
|
||||
" fetch to %s.\n", tid,
|
||||
inst->readPredTarg());
|
||||
} else {
|
||||
panic("Non-control instruction (%s) mispredict"
|
||||
"ing?!!", inst->staticInst->getName());
|
||||
}
|
||||
|
||||
DPRINTF(InOrderExecute, "[tid:%i] Squashing will "
|
||||
"start from stage %i.\n", tid, stage_num);
|
||||
|
||||
cpu->pipelineStage[stage_num]->squashDueToBranch(inst,
|
||||
tid);
|
||||
|
||||
inst->squashingStage = stage_num;
|
||||
|
||||
// Squash throughout other resources
|
||||
cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)
|
||||
ResourcePool::SquashAll,
|
||||
inst, 0, 0, tid);
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i] Squashing from "
|
||||
"stage %i. Redirecting fetch to %s.\n", tid,
|
||||
inst->seqNum, stage_num, pc);
|
||||
DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
|
||||
" misprediction at %s\n", tid, inst->pcState());
|
||||
|
||||
if (inst->predTaken()) {
|
||||
predictedTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
|
||||
"PC %s ... Mispredicts! (Taken)\n",
|
||||
"PC %s ... Mispredicts! "
|
||||
"(Prediction: Taken)\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(
|
||||
inst->instAddr()),
|
||||
@@ -231,7 +174,8 @@ ExecutionUnit::execute(int slot_num)
|
||||
} else {
|
||||
predictedNotTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
|
||||
"PC %s ... Mispredicts! (Not Taken)\n",
|
||||
"PC %s ... Mispredicts! "
|
||||
"(Prediction: Not Taken)\n",
|
||||
tid, inst->seqNum,
|
||||
inst->staticInst->disassemble(
|
||||
inst->instAddr()),
|
||||
@@ -247,7 +191,7 @@ ExecutionUnit::execute(int slot_num)
|
||||
exec_req->done();
|
||||
} else {
|
||||
warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
|
||||
|
||||
inst->fault = fault;
|
||||
exec_req->done();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -78,7 +78,6 @@ FetchSeqUnit::execute(int slot_num)
|
||||
DynInstPtr inst = fs_req->inst;
|
||||
ThreadID tid = inst->readTid();
|
||||
int stage_num = fs_req->getStageNum();
|
||||
InstSeqNum seq_num = inst->seqNum;
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Current PC is %s\n", tid,
|
||||
pc[tid]);
|
||||
@@ -109,48 +108,26 @@ FetchSeqUnit::execute(int slot_num)
|
||||
|
||||
case UpdateTargetPC:
|
||||
{
|
||||
assert(!inst->isCondDelaySlot() &&
|
||||
"Not Handling Conditional Delay Slot");
|
||||
|
||||
if (inst->isControl()) {
|
||||
// If it's a return, then we must wait for resolved address.
|
||||
// The Predictor will mark a return a false as "not taken"
|
||||
// if there is no RAS entry
|
||||
if (inst->isReturn() && !inst->predTaken()) {
|
||||
// If it's a return, then we must wait for resolved address.
|
||||
// The Predictor will mark a return a false as "not taken"
|
||||
// if there is no RAS entry
|
||||
cpu->pipelineStage[stage_num]->
|
||||
toPrevStages->stageBlock[stage_num][tid] = true;
|
||||
pcValid[tid] = false;
|
||||
pcBlockStage[tid] = stage_num;
|
||||
} else if (inst->isCondDelaySlot() && !inst->predTaken()) {
|
||||
assert(0 && "Not Handling Conditional Delay Slot");
|
||||
// Not-Taken AND Conditional Control
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%s] "
|
||||
"Predicted Not-Taken Cond. Delay inst. Skipping "
|
||||
"delay slot and Updating PC to %s\n",
|
||||
tid, inst->seqNum, inst->pcState(),
|
||||
inst->readPredTarg());
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
|
||||
"start from stage %i, after [sn:%i].\n", tid,
|
||||
stage_num, seq_num);
|
||||
|
||||
inst->bdelaySeqNum = seq_num;
|
||||
inst->squashingStage = stage_num;
|
||||
|
||||
squashAfterInst(inst, stage_num, tid);
|
||||
} else if (!inst->isCondDelaySlot() && !inst->predTaken()) {
|
||||
// Not-Taken Control
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted "
|
||||
"Not-Taken Control "
|
||||
"inst. updating PC to %s\n", tid, inst->seqNum,
|
||||
inst->readPredTarg());
|
||||
} else if (inst->predTaken()) {
|
||||
// Taken Control
|
||||
inst->bdelaySeqNum = seq_num;
|
||||
inst->squashingStage = stage_num;
|
||||
inst->setSquashInfo(stage_num);
|
||||
setupSquash(inst, stage_num, tid);
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
|
||||
"start from stage %i, after [sn:%i].\n",
|
||||
tid, stage_num, inst->bdelaySeqNum);
|
||||
|
||||
// Do Squashing
|
||||
squashAfterInst(inst, stage_num, tid);
|
||||
}
|
||||
} else {
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch "
|
||||
@@ -167,17 +144,6 @@ FetchSeqUnit::execute(int slot_num)
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, ThreadID tid)
|
||||
{
|
||||
// Squash In Pipeline Stage
|
||||
cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
|
||||
|
||||
// Schedule Squash Through-out Resource Pool
|
||||
cpu->resPool->scheduleEvent(
|
||||
(InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
|
||||
}
|
||||
|
||||
void
|
||||
FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
@@ -185,25 +151,6 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from %s (%s) "
|
||||
"stage %i.\n", tid, inst->instName(), inst->pcState(),
|
||||
squash_stage);
|
||||
assert(squash_seq_num == inst->seqNum);
|
||||
|
||||
TheISA::PCState nextPC = inst->pcState();
|
||||
assert(inst->staticInst);
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (inst->isControl()) {
|
||||
if (inst->onInstList) {
|
||||
ListIt inst_it = inst->getInstListIt();
|
||||
inst_it++;
|
||||
if (inst_it != cpu->instList[tid].end()) {
|
||||
DynInstPtr delaySlotInst = (*inst_it);
|
||||
if (delaySlotInst->pcState() != nextPC)
|
||||
squash_seq_num = delaySlotInst->seqNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (squashSeqNum[tid] <= squash_seq_num &&
|
||||
lastSquashCycle[tid] == curTick()) {
|
||||
@@ -214,6 +161,45 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
|
||||
squashSeqNum[tid] = squash_seq_num;
|
||||
lastSquashCycle[tid] = curTick();
|
||||
|
||||
TheISA::PCState nextPC;
|
||||
assert(inst->staticInst);
|
||||
if (inst->isControl()) {
|
||||
nextPC = inst->readPredTarg();
|
||||
|
||||
// If we are already fetching this PC then advance to next PC
|
||||
// =======
|
||||
// This should handle ISAs w/delay slots and annulled delay
|
||||
// slots to figure out which is the next PC to fetch after
|
||||
// a mispredict
|
||||
DynInstPtr bdelay_inst = NULL;
|
||||
ListIt bdelay_it;
|
||||
if (inst->onInstList) {
|
||||
bdelay_it = inst->getInstListIt();
|
||||
bdelay_it++;
|
||||
} else {
|
||||
InstSeqNum branch_delay_num = inst->seqNum + 1;
|
||||
bdelay_it = cpu->findInst(branch_delay_num, tid);
|
||||
}
|
||||
|
||||
if (bdelay_it != cpu->instList[tid].end()) {
|
||||
bdelay_inst = (*bdelay_it);
|
||||
}
|
||||
|
||||
if (bdelay_inst) {
|
||||
DPRINTF(Resource, "Evaluating %s v. %s\n",
|
||||
bdelay_inst->pc, nextPC);
|
||||
|
||||
if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextPC = inst->pcState();
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
}
|
||||
|
||||
|
||||
DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
|
||||
tid, nextPC);
|
||||
pc[tid] = nextPC;
|
||||
|
||||
Reference in New Issue
Block a user