* Authors: Kevin Lim
*/
+#include "arch/types.hh"
+#include "arch/isa_traits.hh"
#include "base/trace.hh"
#include "base/traceflags.hh"
#include "cpu/o3/bpred_unit.hh"
template<class Impl>
-TwobitBPredUnit<Impl>::TwobitBPredUnit(Params ¶ms)
- : BP(params.local_predictor_size,
- params.local_ctr_bits,
- params.instShiftAmt),
- BTB(params.BTBEntries,
- params.BTBTagSize,
- params.instShiftAmt),
- RAS(params.RASSize)
+BPredUnit<Impl>::BPredUnit(Params *params)
+ : BTB(params->BTBEntries,
+ params->BTBTagSize,
+ params->instShiftAmt)
{
+ // Setup the selected predictor.
+ if (params->predType == "local") {
+ localBP = new LocalBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->instShiftAmt);
+ predictor = Local;
+ } else if (params->predType == "tournament") {
+ tournamentBP = new TournamentBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->localHistoryTableSize,
+ params->localHistoryBits,
+ params->globalPredictorSize,
+ params->globalHistoryBits,
+ params->globalCtrBits,
+ params->choicePredictorSize,
+ params->choiceCtrBits,
+ params->instShiftAmt);
+ predictor = Tournament;
+ } else {
+ fatal("Invalid BP selected!");
+ }
+
+ for (int i=0; i < Impl::MaxThreads; i++)
+ RAS[i].init(params->RASSize);
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::regStats()
+BPredUnit<Impl>::regStats()
{
lookups
.name(name() + ".BPredUnit.lookups")
usedRAS
.name(name() + ".BPredUnit.usedRAS")
- .desc("Number of times the RAS was used.")
+ .desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
;
}
+template <class Impl>
+void
+BPredUnit<Impl>::switchOut()
+{
+ // Clear any state upon switch out.
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ squash(0, i);
+ }
+}
+
+template <class Impl>
+void
+BPredUnit<Impl>::takeOverFrom()
+{
+ // Can reset all predictor state, but it's not necessarily better
+ // than leaving it be.
+/*
+ for (int i = 0; i < Impl::MaxThreads; ++i)
+ RAS[i].reset();
+
+ BP.reset();
+ BTB.reset();
+*/
+}
+
template <class Impl>
bool
-TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
+BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
- // Once that's done, speculatively update the predictor?
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
++lookups;
+ void *bp_history = NULL;
+
if (inst->isUncondCtrl()) {
- DPRINTF(Fetch, "BranchPred: Unconditional control.\n");
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Unconditional control.\n", tid);
pred_taken = true;
+ // Tell the BP there was an unconditional branch.
+ BPUncond(bp_history);
} else {
++condPredicted;
- pred_taken = BPLookup(PC);
+ pred_taken = BPLookup(PC, bp_history);
- DPRINTF(Fetch, "BranchPred: Branch predictor predicted %i for PC %#x"
- "\n", pred_taken, inst->readPC());
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i "
+ "for PC %#x\n",
+ tid, pred_taken, inst->readPC());
}
- PredictorHistory predict_record(inst->seqNum, PC, pred_taken);
+ PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
+ bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
// If it's a function return call, then look up the address
// in the RAS.
- target = RAS.top();
+ target = RAS[tid].top();
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
- predict_record.RASIndex = RAS.topIdx();
+ predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = target;
- RAS.pop();
+ assert(predict_record.RASIndex < 16);
+
+ RAS[tid].pop();
- DPRINTF(Fetch, "BranchPred: Instruction %#x is a return, RAS "
- "predicted target: %#x, RAS index: %i.\n",
- inst->readPC(), target, predict_record.RASIndex);
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, "
+ "RAS predicted target: %#x, RAS index: %i.\n",
+ tid, inst->readPC(), target, predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
- RAS.push(PC+sizeof(MachInst));
+#if ISA_HAS_DELAY_SLOT
+ Addr ras_pc = PC + (2 * sizeof(MachInst)); // Next Next PC
+#else
+ Addr ras_pc = PC + sizeof(MachInst); // Next PC
+#endif
+ RAS[tid].push(ras_pc);
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
predict_record.wasCall = true;
- DPRINTF(Fetch, "BranchPred: Instruction %#x was a call, "
- "adding %#x to the RAS.\n",
- inst->readPC(), PC+sizeof(MachInst));
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x was a call"
+ ", adding %#x to the RAS index: %i.\n",
+ tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
}
- if (BTB.valid(PC)) {
+ if (BTB.valid(PC, tid)) {
++BTBHits;
- //If it's anything else, use the BTB to get the target addr.
- target = BTB.lookup(PC);
+ // If it's not a return, use the BTB to get the target addr.
+ target = BTB.lookup(PC, tid);
- DPRINTF(Fetch, "BranchPred: Instruction %#x predicted target "
- "is %#x.\n", inst->readPC(), target);
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted"
+ " target is %#x.\n",
+ tid, inst->readPC(), target);
} else {
- DPRINTF(Fetch, "BranchPred: BTB doesn't have a valid entry."
- "\n");
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a "
+ "valid entry.\n",tid);
pred_taken = false;
}
}
}
- if (pred_taken) {
- // Set the PC and the instruction's predicted target.
- PC = target;
- inst->setPredTarg(target);
- } else {
- PC = PC + sizeof(MachInst);
- inst->setPredTarg(PC);
- }
-
- predHist.push_front(predict_record);
+ predHist[tid].push_front(predict_record);
- assert(!predHist.empty());
+ DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());
return pred_taken;
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::update(const InstSeqNum &done_sn)
+BPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid)
{
- DPRINTF(Fetch, "BranchPred: Commiting branches until sequence number "
- "%i.\n", done_sn);
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until "
+ "[sn:%lli].\n", tid, done_sn);
- while (!predHist.empty() && predHist.back().seqNum <= done_sn) {
- assert(!predHist.empty());
+ while (!predHist[tid].empty() &&
+ predHist[tid].back().seqNum <= done_sn) {
+ // Update the branch predictor with the correct results.
+ BPUpdate(predHist[tid].back().PC,
+ predHist[tid].back().predTaken,
+ predHist[tid].back().bpHistory);
- // Update the branch predictor with the correct results of branches.
- BP.update(predHist.back().PC, predHist.back().predTaken);
-
- predHist.pop_back();
+ predHist[tid].pop_back();
}
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn)
+BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid)
{
- while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
- if (predHist.front().usedRAS) {
- DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
- "target: %#x.\n",
- predHist.front().RASIndex,
- predHist.front().RASTarget);
-
- RAS.restore(predHist.front().RASIndex,
- predHist.front().RASTarget);
- } else if (predHist.front().wasCall) {
- DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
- "to the RAS.\n");
-
- RAS.pop();
+ History &pred_hist = predHist[tid];
+
+ while (!pred_hist.empty() &&
+ pred_hist.front().seqNum > squashed_sn) {
+ if (pred_hist.front().usedRAS) {
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
+ " target: %#x.\n",
+ tid,
+ pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ RAS[tid].restore(pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+ } else if (pred_hist.front().wasCall) {
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry "
+ "added to the RAS.\n",tid);
+
+ RAS[tid].pop();
}
- predHist.pop_front();
+ // This call should delete the bpHistory.
+ BPSquash(pred_hist.front().bpHistory);
+
+ pred_hist.pop_front();
}
+
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
- const Addr &corr_target,
- const bool actually_taken)
+BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
+ const Addr &corr_target,
+ const bool actually_taken,
+ unsigned tid)
{
// Now that we know that a branch was mispredicted, we need to undo
// all the branches that have been seen up until this branch and
// fix up everything.
+ History &pred_hist = predHist[tid];
+
++condIncorrect;
- DPRINTF(Fetch, "BranchPred: Squashing from sequence number %i, "
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
"setting target to %#x.\n",
- squashed_sn, corr_target);
+ tid, squashed_sn, corr_target);
- while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
+ squash(squashed_sn, tid);
- if (predHist.front().usedRAS) {
- DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
- "target: %#x.\n",
- predHist.front().RASIndex,
- predHist.front().RASTarget);
+ // If there's a squash due to a syscall, there may not be an entry
+ // corresponding to the squash. In that case, don't bother trying to
+ // fix up the entry.
+ if (!pred_hist.empty()) {
+ assert(pred_hist.front().seqNum == squashed_sn);
+ if (pred_hist.front().usedRAS) {
+ ++RASIncorrect;
+ }
- RAS.restore(predHist.front().RASIndex,
- predHist.front().RASTarget);
- } else if (predHist.front().wasCall) {
- DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
- "to the RAS.\n");
+ BPUpdate(pred_hist.front().PC, actually_taken,
+ pred_hist.front().bpHistory);
- RAS.pop();
- }
+ BTB.update(pred_hist.front().PC, corr_target, tid);
+ pred_hist.pop_front();
+ }
+}
- predHist.pop_front();
+template <class Impl>
+void
+BPredUnit<Impl>::BPUncond(void * &bp_history)
+{
+ // Only the tournament predictor cares about unconditional branches.
+ if (predictor == Tournament) {
+ tournamentBP->uncondBr(bp_history);
}
+}
- predHist.front().predTaken = actually_taken;
+template <class Impl>
+void
+BPredUnit<Impl>::BPSquash(void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->squash(bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->squash(bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+template <class Impl>
+bool
+BPredUnit<Impl>::BPLookup(Addr &inst_PC, void * &bp_history)
+{
+ if (predictor == Local) {
+ return localBP->lookup(inst_PC, bp_history);
+ } else if (predictor == Tournament) {
+ return tournamentBP->lookup(inst_PC, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
- if (predHist.front().usedRAS) {
- ++RASIncorrect;
+template <class Impl>
+void
+BPredUnit<Impl>::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->update(inst_PC, taken, bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->update(inst_PC, taken, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
}
+}
- BP.update(predHist.front().PC, actually_taken);
+template <class Impl>
+void
+BPredUnit<Impl>::dump()
+{
+ typename History::iterator pred_hist_it;
+
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ if (!predHist[i].empty()) {
+ pred_hist_it = predHist[i].begin();
- BTB.update(predHist.front().PC, corr_target);
+ cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
+
+ while (pred_hist_it != predHist[i].end()) {
+ cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
+ "bpHistory:%#x\n",
+ (*pred_hist_it).seqNum, (*pred_hist_it).PC,
+ (*pred_hist_it).tid, (*pred_hist_it).predTaken,
+ (*pred_hist_it).bpHistory);
+ pred_hist_it++;
+ }
+
+ cprintf("\n");
+ }
+ }
}