inorder: use setupSquash for misspeculation

implement a clean interface to handle branch misprediction and eventually all pipeline
flushing
This commit is contained in:
Korey Sewell
2011-06-19 21:43:35 -04:00
parent d5d4e47f76
commit b195da9345
9 changed files with 134 additions and 146 deletions

View File

@@ -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()
{

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -576,6 +576,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted
bool procDelaySlotOnMispred;
void setSquashInfo(unsigned stage_num);
////////////////////////////////////////////
//
// MEMORY ACCESS

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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;