From: Korey Sewell Date: Mon, 20 Jun 2011 01:43:35 +0000 (-0400) Subject: inorder: use setupSquash for misspeculation X-Git-Tag: stable_2012_02_02~250 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b195da9345c00c2961558f80715660c0c0a629fc;p=gem5.git inorder: use setupSquash for misspeculation implement a clean interface to handle branch misprediction and eventually all pipeline flushing --- diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index ce3796528..2e3b0188b 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -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() { diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index a1fc2de52..aad701ff4 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -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); diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index 1bbd4f639..d8bfbacc7 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -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) { diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh index ff60120a3..73e723312 100644 --- a/src/cpu/inorder/inorder_dyn_inst.hh +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -576,6 +576,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted bool procDelaySlotOnMispred; + void setSquashInfo(unsigned stage_num); + //////////////////////////////////////////// // // MEMORY ACCESS diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc index cad5cfb09..23d33afbe 100644 --- a/src/cpu/inorder/resource.cc +++ b/src/cpu/inorder/resource.cc @@ -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) diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index 0f2cde7d1..097497362 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -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); diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc index a34991854..3132770d4 100644 --- a/src/cpu/inorder/resources/branch_predictor.cc +++ b/src/cpu/inorder/resources/branch_predictor.cc @@ -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); } } diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc index ca1f4ade4..4363f125d 100644 --- a/src/cpu/inorder/resources/execution_unit.cc +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -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(); - 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); - - 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; + assert(inst->isControl()); - 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); + // Set up Squash Generated By this Misprediction + unsigned stage_num = exec_req->getStageNum(); + ThreadID tid = inst->readTid(); + TheISA::PCState pc = inst->pcState(); + TheISA::advancePC(pc, inst->staticInst); + inst->setPredTarg(pc); + inst->setSquashInfo(stage_num); - inst->squashingStage = stage_num; + setupSquash(inst, stage_num, tid); - // 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 { diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index 579f9d45b..62dbb452a 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -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;