params->instShiftAmt,
params->numThreads),
RAS(numThreads),
+ useIndirect(params->useIndirect),
+ iPred(params->indirectHashGHR,
+ params->indirectHashTargets,
+ params->indirectSets,
+ params->indirectWays,
+ params->indirectTagSize,
+ params->indirectPathLength,
+ params->instShiftAmt,
+ params->numThreads),
instShiftAmt(params->instShiftAmt)
{
for (auto& r : RAS)
void
BPredUnit::regStats()
{
+ SimObject::regStats();
+
lookups
.name(name() + ".lookups")
.desc("Number of BP lookups")
.name(name() + ".RASInCorrect")
.desc("Number of incorrect RAS predictions.")
;
+
+ indirectLookups
+ .name(name() + ".indirectLookups")
+ .desc("Number of indirect predictor lookups.")
+ ;
+
+ indirectHits
+ .name(name() + ".indirectHits")
+ .desc("Number of indirect target hits.")
+ ;
+
+ indirectMisses
+ .name(name() + ".indirectMisses")
+ .desc("Number of indirect misses.")
+ ;
+
+ indirectMispredicted
+ .name(name() + "indirectMispredicted")
+ .desc("Number of mispredicted indirect branches.")
+ ;
+
}
ProbePoints::PMUUPtr
DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
pred_taken = true;
// Tell the BP there was an unconditional branch.
- uncondBranch(pc.instAddr(), bp_history);
+ uncondBranch(tid, pc.instAddr(), bp_history);
} else {
++condPredicted;
- pred_taken = lookup(pc.instAddr(), bp_history);
+ pred_taken = lookup(tid, pc.instAddr(), bp_history);
DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
" predicted %i for PC %s\n", tid, seqNum, pred_taken, pc);
tid, pc, pc, RAS[tid].topIdx());
}
- if (BTB.valid(pc.instAddr(), tid)) {
- ++BTBHits;
-
- // If it's not a return, use the BTB to get the target addr.
- target = BTB.lookup(pc.instAddr(), tid);
-
- DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
- " target is %s.\n", tid, pc, target);
-
+ if (inst->isDirectCtrl() || !useIndirect) {
+ // Check BTB on direct branches
+ if (BTB.valid(pc.instAddr(), tid)) {
+ ++BTBHits;
+
+ // If it's not a return, use the BTB to get target addr.
+ target = BTB.lookup(pc.instAddr(), tid);
+
+ DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
+ " target is %s.\n", tid, pc, target);
+
+ } else {
+ DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
+ "valid entry.\n",tid);
+ pred_taken = false;
+ // The Direction of the branch predictor is altered
+ // because the BTB did not have an entry
+ // The predictor needs to be updated accordingly
+ if (!inst->isCall() && !inst->isReturn()) {
+ btbUpdate(tid, pc.instAddr(), bp_history);
+ DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
+ " called for %s\n", tid, seqNum, pc);
+ } else if (inst->isCall() && !inst->isUncondCtrl()) {
+ RAS[tid].pop();
+ predict_record.pushedRAS = false;
+ }
+ TheISA::advancePC(target, inst);
+ }
} else {
- DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
- "valid entry.\n",tid);
- pred_taken = false;
- // The Direction of the branch predictor is altered because the
- // BTB did not have an entry
- // The predictor needs to be updated accordingly
- if (!inst->isCall() && !inst->isReturn()) {
- btbUpdate(pc.instAddr(), bp_history);
- DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
- " called for %s\n", tid, seqNum, pc);
- } else if (inst->isCall() && !inst->isUncondCtrl()) {
- RAS[tid].pop();
- predict_record.pushedRAS = false;
+ predict_record.wasIndirect = true;
+ ++indirectLookups;
+ //Consult indirect predictor on indirect control
+ if (iPred.lookup(pc.instAddr(), getGHR(tid, bp_history),
+ target, tid)) {
+ // Indirect predictor hit
+ ++indirectHits;
+ DPRINTF(Branch, "[tid:%i]: Instruction %s predicted "
+ "indirect target is %s.\n", tid, pc, target);
+ } else {
+ ++indirectMisses;
+ pred_taken = false;
+ DPRINTF(Branch, "[tid:%i]: Instruction %s no indirect "
+ "target.\n", tid, pc);
+ if (!inst->isCall() && !inst->isReturn()) {
+
+ } else if (inst->isCall() && !inst->isUncondCtrl()) {
+ RAS[tid].pop();
+ predict_record.pushedRAS = false;
+ }
+ TheISA::advancePC(target, inst);
}
- TheISA::advancePC(target, inst);
+ iPred.recordIndirect(pc.instAddr(), target.instAddr(), seqNum,
+ tid);
}
}
} else {
return pred_taken;
}
-bool
-BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
- int asid, TheISA::PCState &instPC,
- TheISA::PCState &predPC, ThreadID tid)
-{
- // See if branch predictor predicts taken.
- // If so, get its target addr either from the BTB or the RAS.
- // Save off record of branch stuff so the RAS can be fixed
- // up once it's done.
-
- using TheISA::MachInst;
-
- bool pred_taken = false;
- TheISA::PCState target;
-
- ++lookups;
- ppBranches->notify(1);
-
- DPRINTF(Branch, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
- "prediction\n", tid, seqNum,
- inst->disassemble(instPC.instAddr()), instPC);
-
- void *bp_history = NULL;
-
- if (inst->isUncondCtrl()) {
- DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
- pred_taken = true;
- // Tell the BP there was an unconditional branch.
- uncondBranch(instPC.instAddr(), bp_history);
-
- if (inst->isReturn() && RAS[tid].empty()) {
- DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
- "false.\n", tid);
- pred_taken = false;
- }
- } else {
- ++condPredicted;
-
- pred_taken = lookup(predPC.instAddr(), bp_history);
- }
-
- PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
- bp_history, tid);
-
- // Now lookup in the BTB or RAS.
- if (pred_taken) {
- if (inst->isReturn()) {
- ++usedRAS;
-
- // If it's a function return call, then look up the address
- // in the RAS.
- TheISA::PCState rasTop = RAS[tid].top();
- target = TheISA::buildRetPC(instPC, rasTop);
-
- // Record the top entry of the RAS, and its index.
- predict_record.usedRAS = true;
- predict_record.RASIndex = RAS[tid].topIdx();
- predict_record.RASTarget = rasTop;
-
- assert(predict_record.RASIndex < 16);
-
- RAS[tid].pop();
-
- DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
- "RAS predicted target: %s, RAS index: %i.\n",
- tid, instPC, target,
- predict_record.RASIndex);
- } else {
- ++BTBLookups;
-
- if (inst->isCall()) {
-
- RAS[tid].push(instPC);
- predict_record.pushedRAS = true;
-
- // 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(Branch, "[tid:%i]: Instruction %s was a call"
- ", adding %s to the RAS index: %i.\n",
- tid, instPC, predPC,
- RAS[tid].topIdx());
- }
-
- if (inst->isCall() &&
- inst->isUncondCtrl() &&
- inst->isDirectCtrl()) {
- target = inst->branchTarget(instPC);
- } else if (BTB.valid(predPC.instAddr(), asid)) {
- ++BTBHits;
-
- // If it's not a return, use the BTB to get the target addr.
- target = BTB.lookup(predPC.instAddr(), asid);
-
- DPRINTF(Branch, "[tid:%i]: [asid:%i] Instruction %s "
- "predicted target is %s.\n",
- tid, asid, instPC, target);
- } else {
- DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
- "valid entry, predicting false.\n",tid);
- pred_taken = false;
- }
- }
- }
-
- if (pred_taken) {
- // Set the PC and the instruction's predicted target.
- predPC = target;
- }
- DPRINTF(Branch, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
- tid, seqNum, predPC);
-
- predHist[tid].push_front(predict_record);
-
- DPRINTF(Branch, "[tid:%i] [sn:%i] pushed onto front of predHist "
- "...predHist.size(): %i\n",
- tid, seqNum, predHist[tid].size());
-
- return pred_taken;
-}
-
void
BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
{
DPRINTF(Branch, "[tid:%i]: Committing branches until "
"[sn:%lli].\n", tid, done_sn);
+ iPred.commit(done_sn, tid);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
- if (!predHist[tid].back().wasSquashed) {
- update(predHist[tid].back().pc, predHist[tid].back().predTaken,
- predHist[tid].back().bpHistory, false);
- } else {
- retireSquashed(predHist[tid].back().bpHistory);
- }
+ update(tid, predHist[tid].back().pc,
+ predHist[tid].back().predTaken,
+ predHist[tid].back().bpHistory, false);
predHist[tid].pop_back();
}
{
History &pred_hist = predHist[tid];
+ iPred.squash(squashed_sn, tid);
while (!pred_hist.empty() &&
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().usedRAS) {
}
// This call should delete the bpHistory.
- squash(pred_hist.front().bpHistory);
+ squash(tid, pred_hist.front().bpHistory);
DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
"PC %s.\n", tid, pred_hist.front().seqNum,
if ((*hist_it).usedRAS) {
++RASIncorrect;
+ DPRINTF(Branch, "[tid:%i]: Incorrect RAS [sn:%i]\n",
+ tid, hist_it->seqNum);
}
- update((*hist_it).pc, actually_taken,
+ // Get the underlying Global History Register
+ unsigned ghr = getGHR(tid, hist_it->bpHistory);
+
+ // There are separate functions for in-order and out-of-order
+ // branch prediction, but not for update. Therefore, this
+ // call should take into account that the mispredicted branch may
+ // be on the wrong path (i.e., OoO execution), and that the counter
+ // counter table(s) should not be updated. Thus, this call should
+ // restore the state of the underlying predictor, for instance the
+ // local/global histories. The counter tables will be updated when
+ // the branch actually commits.
+
+ // Remember the correct direction for the update at commit.
+ pred_hist.front().predTaken = actually_taken;
+
+ update(tid, (*hist_it).pc, actually_taken,
pred_hist.front().bpHistory, true);
- hist_it->wasSquashed = true;
if (actually_taken) {
if (hist_it->wasReturn && !hist_it->usedRAS) {
RAS[tid].pop();
hist_it->usedRAS = true;
}
+ if (hist_it->wasIndirect) {
+ ++indirectMispredicted;
+ iPred.recordTarget(hist_it->seqNum, ghr, corrTarget, tid);
+ } else {
+ DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
+ " PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
- DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
- " PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
-
- BTB.update((*hist_it).pc, corrTarget, tid);
-
+ BTB.update((*hist_it).pc, corrTarget, tid);
+ }
} else {
//Actually not Taken
if (hist_it->usedRAS) {