cpu: Branch Predictor Refactoring

Major refactoring of the branch predictor unit.
- Clearer control flow of the main branch predictor
- Remove `uncondBranch` and `btbUpdate` functions in favour of a
  common `historyUpdate` function. There is now only one lookup
  function for conditional branches and the new `historyUpdate` for
  speculative history update.
- Added a new *target provider* class.
- More expressive statistics depending on the different branch types.
- Cleanup the branch history management

Change-Id: I21fa555b5663e4abad7c836fc1d41a9c8b205263
Signed-off-by: David Schall <david.schall@ed.ac.uk>
This commit is contained in:
David Schall
2023-10-17 15:16:54 +00:00
parent 531067fffa
commit ccbb85c67f
22 changed files with 1079 additions and 680 deletions

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -67,10 +79,10 @@ LocalBP::LocalBP(const LocalBPParams &params)
}
void
LocalBP::btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history)
LocalBP::updateHistories(ThreadID tid, Addr pc, bool uncond,
bool taken, Addr target, void * &bp_history)
{
// Place holder for a function that is called to update predictor history when
// a BTB entry is invalid or not found.
// Place holder for a function that is called to update predictor history
}
@@ -94,8 +106,8 @@ LocalBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
}
void
LocalBP::update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget)
LocalBP::update(ThreadID tid, Addr branch_addr, bool taken, void *&bp_history,
bool squashed, const StaticInstPtr & inst, Addr target)
{
assert(bp_history == NULL);
unsigned local_predictor_idx;
@@ -135,10 +147,6 @@ LocalBP::getLocalIndex(Addr &branch_addr)
return (branch_addr >> instShiftAmt) & indexMask;
}
void
LocalBP::uncondBranch(ThreadID tid, Addr pc, void *&bp_history)
{
}
} // namespace branch_prediction
} // namespace gem5

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2011, 2014 ARM Limited
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -69,35 +70,17 @@ class LocalBP : public BPredUnit
*/
LocalBP(const LocalBPParams &params);
virtual void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
// Overriding interface functions
bool lookup(ThreadID tid, Addr pc, void * &bp_history) override;
/**
* Looks up the given address in the branch predictor and returns
* a true/false value as to whether it is taken.
* @param branch_addr The address of the branch to look up.
* @param bp_history Pointer to any bp history state.
* @return Whether or not the branch is taken.
*/
bool lookup(ThreadID tid, Addr branch_addr, void * &bp_history);
void updateHistories(ThreadID tid, Addr pc, bool uncond, bool taken,
Addr target, void * &bp_history) override;
/**
* Updates the branch predictor to Not Taken if a BTB entry is
* invalid or not found.
* @param branch_addr The address of the branch to look up.
* @param bp_history Pointer to any bp history state.
* @return Whether or not the branch is taken.
*/
void btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history);
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
/**
* Updates the branch predictor with the actual result of a branch.
* @param branch_addr The address of the branch to update.
* @param taken Whether or not the branch was taken.
*/
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget);
void squash(ThreadID tid, void *bp_history)
void squash(ThreadID tid, void * &bp_history) override
{ assert(bp_history == NULL); }
private:

View File

@@ -57,6 +57,15 @@ class BranchType(Enum):
]
class TargetProvider(Enum):
vals = [
"NoTarget",
"BTB",
"RAS",
"Indirect",
]
class ReturnAddrStack(SimObject):
type = "ReturnAddrStack"
cxx_class = "gem5::branch_prediction::ReturnAddrStack"

View File

@@ -59,7 +59,7 @@ SimObject('BranchPredictor.py',
'MultiperspectivePerceptronTAGE64KB', 'MPP_TAGE_8KB',
'MPP_LoopPredictor_8KB', 'MPP_StatisticalCorrector_8KB',
'MultiperspectivePerceptronTAGE8KB'],
enums=['BranchType'])
enums=['BranchType', 'TargetProvider'])
Source('bpred_unit.cc')
Source('2bit_local.cc')

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The Regents of The University of Michigan
* All rights reserved.
*
@@ -73,7 +85,7 @@ BiModeBP::BiModeBP(const BiModeBPParams &params)
* chooses the taken array and the taken array predicts taken.
*/
void
BiModeBP::uncondBranch(ThreadID tid, Addr pc, void * &bpHistory)
BiModeBP::uncondBranch(ThreadID tid, Addr pc, void * &bp_history)
{
BPHistory *history = new BPHistory;
history->globalHistoryReg = globalHistoryReg[tid];
@@ -81,17 +93,29 @@ BiModeBP::uncondBranch(ThreadID tid, Addr pc, void * &bpHistory)
history->takenPred = true;
history->notTakenPred = true;
history->finalPred = true;
bpHistory = static_cast<void*>(history);
updateGlobalHistReg(tid, true);
bp_history = static_cast<void*>(history);
}
void
BiModeBP::squash(ThreadID tid, void *bpHistory)
BiModeBP::updateHistories(ThreadID tid, Addr pc, bool uncond,
bool taken, Addr target, void * &bp_history)
{
BPHistory *history = static_cast<BPHistory*>(bpHistory);
assert(uncond || bp_history);
if (uncond) {
uncondBranch(tid, pc, bp_history);
}
updateGlobalHistReg(tid, taken);
}
void
BiModeBP::squash(ThreadID tid, void * &bp_history)
{
BPHistory *history = static_cast<BPHistory*>(bp_history);
globalHistoryReg[tid] = history->globalHistoryReg;
delete history;
bp_history = nullptr;
}
/*
@@ -104,7 +128,7 @@ BiModeBP::squash(ThreadID tid, void *bpHistory)
* direction predictors for the final branch prediction.
*/
bool
BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bpHistory)
BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bp_history)
{
unsigned choiceHistoryIdx = ((branchAddr >> instShiftAmt)
& choiceHistoryMask);
@@ -136,17 +160,11 @@ BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bpHistory)
}
history->finalPred = finalPrediction;
bpHistory = static_cast<void*>(history);
updateGlobalHistReg(tid, finalPrediction);
bp_history = static_cast<void*>(history);
return finalPrediction;
}
void
BiModeBP::btbUpdate(ThreadID tid, Addr branchAddr, void * &bpHistory)
{
globalHistoryReg[tid] &= (historyRegisterMask & ~1ULL);
}
/* Only the selected direction predictor will be updated with the final
* outcome; the status of the unselected one will not be altered. The choice
@@ -155,12 +173,12 @@ BiModeBP::btbUpdate(ThreadID tid, Addr branchAddr, void * &bpHistory)
* the direction predictors makes a correct final prediction.
*/
void
BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken, void *bpHistory,
bool squashed, const StaticInstPtr & inst, Addr corrTarget)
BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken,void * &bp_history,
bool squashed, const StaticInstPtr & inst, Addr target)
{
assert(bpHistory);
assert(bp_history);
BPHistory *history = static_cast<BPHistory*>(bpHistory);
BPHistory *history = static_cast<BPHistory*>(bp_history);
// We do not update the counters speculatively on a squash.
// We just restore the global history register.
@@ -222,6 +240,7 @@ BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken, void *bpHistory,
}
delete history;
bp_history = nullptr;
}
void

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The Regents of The University of Michigan
* All rights reserved.
*
@@ -61,15 +73,17 @@ class BiModeBP : public BPredUnit
{
public:
BiModeBP(const BiModeBPParams &params);
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
void squash(ThreadID tid, void *bp_history);
bool lookup(ThreadID tid, Addr branch_addr, void * &bp_history);
void btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history);
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget);
bool lookup(ThreadID tid, Addr pc, void * &bp_history) override;
void updateHistories(ThreadID tid, Addr pc, bool uncond, bool taken,
Addr target, void * &bp_history) override;
void squash(ThreadID tid, void * &bp_history) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
private:
void updateGlobalHistReg(ThreadID tid, bool taken);
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
struct BPHistory
{

View File

@@ -58,45 +58,15 @@ namespace branch_prediction
BPredUnit::BPredUnit(const Params &params)
: SimObject(params),
numThreads(params.numThreads),
instShiftAmt(params.instShiftAmt),
predHist(numThreads),
btb(params.btb),
ras(params.ras),
iPred(params.indirectBranchPred),
stats(this),
instShiftAmt(params.instShiftAmt)
stats(this)
{
}
BPredUnit::BPredUnitStats::BPredUnitStats(statistics::Group *parent)
: statistics::Group(parent),
ADD_STAT(lookups, statistics::units::Count::get(),
"Number of BP lookups"),
ADD_STAT(condPredicted, statistics::units::Count::get(),
"Number of conditional branches predicted"),
ADD_STAT(condIncorrect, statistics::units::Count::get(),
"Number of conditional branches incorrect"),
ADD_STAT(BTBLookups, statistics::units::Count::get(),
"Number of BTB lookups"),
ADD_STAT(BTBUpdates, statistics::units::Count::get(),
"Number of BTB updates"),
ADD_STAT(BTBHits, statistics::units::Count::get(), "Number of BTB hits"),
ADD_STAT(BTBHitRatio, statistics::units::Ratio::get(), "BTB Hit Ratio",
BTBHits / BTBLookups),
ADD_STAT(RASUsed, statistics::units::Count::get(),
"Number of times the RAS was used to get a target."),
ADD_STAT(RASIncorrect, statistics::units::Count::get(),
"Number of incorrect RAS predictions."),
ADD_STAT(indirectLookups, statistics::units::Count::get(),
"Number of indirect predictor lookups."),
ADD_STAT(indirectHits, statistics::units::Count::get(),
"Number of indirect target hits."),
ADD_STAT(indirectMisses, statistics::units::Count::get(),
"Number of indirect misses."),
ADD_STAT(indirectMispredicted, statistics::units::Count::get(),
"Number of mispredicted indirect branches.")
{
BTBHitRatio.precision(6);
}
probing::PMUUPtr
BPredUnit::pmuProbePoint(const char *name)
@@ -123,246 +93,350 @@ BPredUnit::drainSanityCheck() const
assert(ph.empty());
}
bool
BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
PCStateBase &pc, ThreadID tid)
{
/** Perform the prediction. */
PredictorHistory* bpu_history = nullptr;
bool taken = predict(inst, seqNum, pc, tid, bpu_history);
assert(bpu_history!=nullptr);
/** Push the record into the history buffer */
predHist[tid].push_front(bpu_history);
DPRINTF(Branch, "[tid:%i] [sn:%llu] History entry added. "
"predHist.size(): %i\n", tid, seqNum, predHist[tid].size());
return taken;
}
bool
BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
PCStateBase &pc, ThreadID tid, PredictorHistory* &hist)
{
assert(hist == nullptr);
// 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.
// Save off branch stuff into `hist` so we can correct the predictor
// if prediction was wrong.
bool pred_taken = false;
std::unique_ptr<PCStateBase> target(pc.clone());
BranchType brType = getBranchType(inst);
hist = new PredictorHistory(tid, seqNum, pc.instAddr(), inst);
++stats.lookups;
stats.lookups[tid][brType]++;
ppBranches->notify(1);
void *bp_history = NULL;
void *indirect_history = NULL;
/* -----------------------------------------------
* Get branch direction
* -----------------------------------------------
* Lookup the direction predictor for every
* conditional branch. For unconditional branches
* the direction is always taken
*/
if (inst->isUncondCtrl()) {
DPRINTF(Branch, "[tid:%i] [sn:%llu] Unconditional control\n",
tid,seqNum);
pred_taken = true;
// Tell the BP there was an unconditional branch.
uncondBranch(tid, pc.instAddr(), bp_history);
// Unconditional branches -----
hist->condPred = true;
} else {
// Conditional branches -------
++stats.condPredicted;
pred_taken = lookup(tid, pc.instAddr(), bp_history);
hist->condPred = lookup(tid, pc.instAddr(), hist->bpHistory);
DPRINTF(Branch, "[tid:%i] [sn:%llu] "
"Branch predictor predicted %i for PC %s\n",
tid, seqNum, pred_taken, pc);
if (hist->condPred) {
++stats.condPredictedTaken;
}
}
hist->predTaken = hist->condPred;
DPRINTF(Branch,
"[tid:%i] [sn:%llu] Creating prediction history for PC %s\n",
tid, seqNum, pc);
"[tid:%i, sn:%llu] Branch predictor predicted %i for PC:%#x %s\n",
tid, seqNum, hist->condPred, hist->pc, toString(brType));
PredictorHistory predict_record(seqNum, pc.instAddr(), pred_taken,
bp_history, indirect_history, tid, inst);
// Now lookup in the BTB or RAS.
if (pred_taken) {
// Note: The RAS may be both popped and pushed to
// support coroutines.
if (inst->isReturn()) {
++stats.RASUsed;
// If it's a return from a function call, then look up the
// RETURN address in the RAS.
const PCStateBase *return_addr = ras->pop(tid,
predict_record.rasHistory);
if (return_addr)
set(target, return_addr);
// The direction is done now get the target address
// from BTB, RAS or indirect predictor.
hist->targetProvider = TargetProvider::NoTarget;
DPRINTF(Branch, "[tid:%i] [sn:%llu] Instruction %s is a return, "
"RAS predicted target: %s, RAS index: %i\n",
tid, seqNum, pc, *target, predict_record.RASIndex);
/* -----------------------------------------------
* Branch Target Buffer (BTB)
* -----------------------------------------------
* The BTB will be checked for all branches.
*/
stats.BTBLookups++;
const PCStateBase * btb_target = btb->lookup(tid, pc.instAddr(), brType);
if (btb_target) {
stats.BTBHits++;
hist->btbHit = true;
if (hist->predTaken) {
hist->targetProvider = TargetProvider::BTB;
set(hist->target, btb_target);
}
}
DPRINTF(Branch, "[tid:%i, sn:%llu] PC:%#x BTB:%s\n",
tid, seqNum, hist->pc, (hist->btbHit) ? "hit" : "miss");
/* -----------------------------------------------
* Return Address Stack (RAS)
* -----------------------------------------------
* Perform RAS operations for calls and returns.
* Calls: push their RETURN address onto
* the RAS.
* Return: pop the the return address from the
* top of the RAS.
*/
if (ras) {
if (inst->isCall()) {
// In case of a call build the return address and
// push it to the RAS.
auto return_addr = inst->buildRetPC(pc, pc);
ras->push(tid, *return_addr, predict_record.rasHistory);
ras->push(tid, *return_addr, hist->rasHistory);
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
DPRINTF(Branch, "[tid:%i] [sn:%llu] Instr. %s was "
"a call, push return address %s onto the RAS\n",
tid, seqNum, pc, *return_addr);
}
else if (inst->isReturn()) {
// The target address is not predicted by RAS.
// Thus, BTB/IndirectBranch Predictor is employed.
if (!inst->isReturn()) {
if (inst->isDirectCtrl() || !iPred) {
++stats.BTBLookups;
// Check BTB on direct branches
const PCStateBase * btb_target = btb->lookup(tid,
pc.instAddr(),
getBranchType(inst));
if (btb_target) {
++stats.BTBHits;
// If it's not a return, use the BTB to get target addr.
set(target, btb_target);
DPRINTF(Branch,
"[tid:%i] [sn:%llu] Instruction %s predicted "
"target is %s\n",
tid, seqNum, pc, *target);
} else {
DPRINTF(Branch, "[tid:%i] [sn:%llu] BTB doesn't have a "
"valid entry\n", tid, seqNum);
pred_taken = false;
predict_record.predTaken = pred_taken;
// 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:%llu] btbUpdate "
"called for %s\n",
tid, seqNum, pc);
} else if (inst->isCall() && !inst->isUncondCtrl()) {
ras->squash(tid, predict_record.rasHistory);
predict_record.pushedRAS = false;
}
inst->advancePC(*target);
}
} else {
predict_record.wasIndirect = true;
++stats.indirectLookups;
//Consult indirect predictor on indirect control
const PCStateBase *itarget = iPred->lookup(tid,
seqNum, pc.instAddr(),
predict_record.indirectHistory);
if (itarget) {
// Indirect predictor hit
++stats.indirectHits;
set(target, *itarget);
// If it's a return from a function call, then look up the
// RETURN address in the RAS.
const PCStateBase *return_addr = ras->pop(tid, hist->rasHistory);
if (return_addr) {
DPRINTF(Branch,
"[tid:%i, sn:%llu] Instruction %s predicted "
"indirect target is %s\n",
tid, seqNum, pc, *target);
} else {
++stats.indirectMisses;
pred_taken = false;
predict_record.predTaken = pred_taken;
DPRINTF(Branch,
"[tid:%i, sn:%llu] PC:%#x no indirect target\n",
tid, seqNum, pc.instAddr());
// Set the target to the return address
set(hist->target, *return_addr);
hist->targetProvider = TargetProvider::RAS;
if (!inst->isCall() && !inst->isReturn()) {
} else if (inst->isCall() && !inst->isUncondCtrl()) {
ras->squash(tid, predict_record.rasHistory);
}
inst->advancePC(*target);
}
DPRINTF(Branch, "[tid:%i] [sn:%llu] Instr. %s is a "
"return, RAS poped return addr: %s\n",
tid, seqNum, pc, *hist->target);
}
}
} else {
inst->advancePC(*target);
}
predict_record.target = target->instAddr();
set(pc, *target);
/* -----------------------------------------------
* Indirect Predictor
* -----------------------------------------------
* For indirect branches/calls check the indirect
* predictor if one is available. Not for returns.
* Note that depending on the implementation a
* indirect predictor might only return a target
* for an indirect branch with a changing target.
* As most indirect branches have a static target
* using the target from the BTB is the optimal
* to save space in the indirect predictor itself.
*/
if (iPred && hist->predTaken &&
inst->isIndirectCtrl() && !inst->isReturn()) {
++stats.indirectLookups;
const PCStateBase *itarget = iPred->lookup(tid, seqNum,
pc.instAddr(),
hist->indirectHistory);
if (itarget) {
// Indirect predictor hit
++stats.indirectHits;
hist->targetProvider = TargetProvider::Indirect;
set(hist->target, *itarget);
DPRINTF(Branch,
"[tid:%i, sn:%llu] Instruction %s predicted "
"indirect target is %s\n",
tid, seqNum, pc, *hist->target);
} else {
++stats.indirectMisses;
DPRINTF(Branch,
"[tid:%i, sn:%llu] PC:%#x no indirect target\n",
tid, seqNum, pc.instAddr());
}
}
/** ----------------------------------------------
* Fallthrough
* -----------------------------------------------
* All the target predictors did their job.
* If there is no target its either not taken or
* a BTB miss. In that case we just fallthrough.
* */
if (hist->targetProvider == TargetProvider::NoTarget) {
set(hist->target, pc);
inst->advancePC(*hist->target);
hist->predTaken = false;
}
stats.targetProvider[tid][hist->targetProvider]++;
// The actual prediction is done.
// For now the BPU assume its correct. The update
// functions will correct the branch if needed.
// If prediction and actual direction are the same
// at commit the prediction was correct.
hist->actuallyTaken = hist->predTaken;
set(pc, *hist->target);
DPRINTF(Branch, "%s(tid:%i, sn:%i, PC:%#x, %s) -> taken:%i, target:%s "
"provider:%s\n", __func__, tid, seqNum, hist->pc,
toString(brType), hist->predTaken, *hist->target,
enums::TargetProviderStrings[hist->targetProvider]);
/** ----------------------------------------------
* Speculative history update
* -----------------------------------------------
* Now that the prediction is done the predictor
* may update its histories speculative. (local
* and global path). A later squash will revert
* the history update if needed.
* The actual prediction tables will updated once
* we know the correct direction.
**/
updateHistories(tid, hist->pc, hist->uncond, hist->predTaken,
hist->target->instAddr(), hist->bpHistory);
if (iPred) {
// Update the indirect predictor with the direction prediction
iPred->update(tid, seqNum, predict_record.pc, false,
predict_record.predTaken, *target,
getBranchType(inst),
predict_record.indirectHistory);
iPred->update(tid, seqNum, hist->pc, false, hist->predTaken,
*hist->target, brType, hist->indirectHistory);
}
predHist[tid].push_front(predict_record);
DPRINTF(Branch,
"[tid:%i] [sn:%llu] History entry added. "
"predHist.size(): %i\n",
tid, seqNum, predHist[tid].size());
return pred_taken;
return hist->predTaken;
}
void
BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
{
DPRINTF(Branch, "[tid:%i] Committing branches until "
"sn:%llu]\n", tid, done_sn);
"[sn:%llu]\n", tid, done_sn);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
update(tid, predHist[tid].back().pc,
predHist[tid].back().predTaken,
predHist[tid].back().bpHistory, false,
predHist[tid].back().inst,
predHist[tid].back().target);
predHist[tid].back()->seqNum <= done_sn) {
// Commite also Indirect predictor and RAS
if (iPred) {
iPred->commit(tid, predHist[tid].back().seqNum,
predHist[tid].back().indirectHistory);
}
if (ras) {
ras->commit(tid, predHist[tid].back().mispredict,
getBranchType(predHist[tid].back().inst),
predHist[tid].back().rasHistory);
}
// Iterate from the back to front. Least recent
// sequence number until the most recent done number
commitBranch(tid, *predHist[tid].rbegin());
delete predHist[tid].back();
predHist[tid].pop_back();
DPRINTF(Branch, "[tid:%i] [commit sn:%llu] pred_hist.size(): %i\n",
tid, done_sn, predHist[tid].size());
}
}
void
BPredUnit::commitBranch(ThreadID tid, PredictorHistory* &hist)
{
stats.committed[tid][hist->type]++;
if (hist->mispredict) {
stats.mispredicted[tid][hist->type]++;
}
DPRINTF(Branch, "Commit branch: sn:%llu, PC:%#x %s, "
"pred:%i, taken:%i, target:%#x\n",
hist->seqNum, hist->pc, toString(hist->type),
hist->predTaken, hist->actuallyTaken,
hist->target->instAddr());
// Update the branch predictor with the correct results.
update(tid, hist->pc,
hist->actuallyTaken,
hist->bpHistory, false,
hist->inst,
hist->target->instAddr());
// Commite also Indirect predictor and RAS
if (iPred) {
iPred->commit(tid, hist->seqNum,
hist->indirectHistory);
}
if (ras) {
ras->commit(tid, hist->mispredict,
hist->type,
hist->rasHistory);
}
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
{
History &pred_hist = predHist[tid];
while (!pred_hist.empty() &&
pred_hist.front().seqNum > squashed_sn) {
while (!predHist[tid].empty() &&
predHist[tid].front()->seqNum > squashed_sn) {
if (pred_hist.front().rasHistory) {
assert(ras);
auto hist = predHist[tid].front();
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] Incorrect call/return "
"PC %#x. Fix RAS.\n", tid, pred_hist.front().seqNum,
pred_hist.front().pc);
squashHistory(tid, hist);
ras->squash(tid, pred_hist.front().rasHistory);
}
DPRINTF(Branch, "[tid:%i, squash sn:%llu] Removing history for "
"sn:%llu, PC:%#x\n", tid, squashed_sn, hist->seqNum,
hist->pc);
// This call should delete the bpHistory.
squash(tid, pred_hist.front().bpHistory);
if (iPred) {
iPred->squash(tid, pred_hist.front().seqNum,
pred_hist.front().indirectHistory);
}
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] "
"Removing history for [sn:%llu] "
"PC %#x\n", tid, squashed_sn, pred_hist.front().seqNum,
pred_hist.front().pc);
delete predHist[tid].front();
predHist[tid].pop_front();
pred_hist.pop_front();
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] predHist.size(): %i\n",
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] pred_hist.size(): %i\n",
tid, squashed_sn, predHist[tid].size());
}
}
void
BPredUnit::squashHistory(ThreadID tid, PredictorHistory* &history)
{
stats.squashes[tid][history->type]++;
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] Incorrect: %s\n",
tid, history->seqNum,
toString(history->type));
if (history->rasHistory) {
assert(ras);
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] Incorrect call/return "
"PC %#x. Fix RAS.\n", tid, history->seqNum,
history->pc);
ras->squash(tid, history->rasHistory);
}
if (iPred) {
iPred->squash(tid, history->seqNum,
history->indirectHistory);
}
// This call should delete the bpHistory.
squash(tid, history->bpHistory);
}
void
BPredUnit::squash(const InstSeqNum &squashed_sn,
const PCStateBase &corr_target,
bool actually_taken, ThreadID tid)
bool actually_taken, ThreadID tid, bool from_commit)
{
// 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
@@ -380,10 +454,15 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
++stats.condIncorrect;
ppMisses->notify(1);
DPRINTF(Branch, "[tid:%i] Squashing from sequence number %i, "
"setting target to %s\n", tid, squashed_sn, corr_target);
DPRINTF(Branch, "[tid:%i] Squash from %s start from sequence number %i, "
"setting target to %s\n", tid, from_commit ? "commit" : "decode",
squashed_sn, corr_target);
// dump();
// Squash All Branches AFTER this mispredicted branch
// First the Prefetch history then the main history.
squash(squashed_sn, tid);
// If there's a squash due to a syscall, there may not be an entry
@@ -391,25 +470,32 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
// fix up the entry.
if (!pred_hist.empty()) {
auto hist_it = pred_hist.begin();
//HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
// squashed_sn);
PredictorHistory* const hist = pred_hist.front();
//assert(hist_it != pred_hist.end());
if (pred_hist.front().seqNum != squashed_sn) {
DPRINTF(Branch, "Front sn %i != Squash sn %i\n",
pred_hist.front().seqNum, squashed_sn);
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] Mispredicted: %s, PC:%#x\n",
tid, squashed_sn, toString(hist->type), hist->pc);
assert(pred_hist.front().seqNum == squashed_sn);
// Update stats
stats.corrected[tid][hist->type]++;
if (hist->target &&
(hist->target->instAddr() != corr_target.instAddr())) {
stats.targetWrong[tid][hist->targetProvider]++;
}
if ((*hist_it).rasHistory) {
++stats.RASIncorrect;
DPRINTF(Branch,
"[tid:%i] [squash sn:%llu] Incorrect RAS [sn:%llu]\n",
tid, squashed_sn, hist_it->seqNum);
// If the squash is comming from decode it can be
// redirected earlier. Note that this branch might never get
// committed as a preceeding branch was mispredicted
if (!from_commit) {
stats.earlyResteers[tid][hist->type]++;
}
if (actually_taken) {
++stats.NotTakenMispredicted;
} else {
++stats.TakenMispredicted;
}
// 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
@@ -419,99 +505,109 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
// 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;
pred_hist.front().target = corr_target.instAddr();
pred_hist.front().mispredict = true;
// Remember the correct direction and target for the update at commit.
hist->mispredict = true;
hist->actuallyTaken = actually_taken;
set(hist->target, corr_target);
// Correct Direction predictor ------------------
update(tid, hist->pc, actually_taken, hist->bpHistory,
true, hist->inst, corr_target.instAddr());
update(tid, (*hist_it).pc, actually_taken,
pred_hist.front().bpHistory, true, pred_hist.front().inst,
corr_target.instAddr());
// Correct Indirect predictor -------------------
if (iPred) {
iPred->update(tid, squashed_sn, (*hist_it).pc,
iPred->update(tid, squashed_sn, hist->pc,
true, actually_taken, corr_target,
getBranchType(pred_hist.front().inst),
(*hist_it).indirectHistory);
hist->type, hist->indirectHistory);
}
// Correct RAS ---------------------------------
if (ras) {
// The branch was taken and the RAS was not updated.
// In case of call or return that needs to be fixed.
if (actually_taken && (hist_it->rasHistory == nullptr)) {
if (actually_taken && (hist->rasHistory == nullptr)) {
// A return has not poped the RAS.
if (hist_it->inst->isReturn()) {
if (hist->type == BranchType::Return) {
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] "
"Incorrectly predicted return [sn:%llu] PC: %#x\n",
tid, squashed_sn, hist_it->seqNum, hist_it->pc);
tid, squashed_sn, hist->seqNum, hist->pc);
ras->pop(tid, hist_it->rasHistory);
ras->pop(tid, hist->rasHistory);
}
// A call has not pushed a return address to the RAS.
if (hist_it->inst->isCall()) {
if (hist->call) {
// In case of a call build the return address and
// push it to the RAS.
auto return_addr = hist_it->inst->buildRetPC(
auto return_addr = hist->inst->buildRetPC(
corr_target, corr_target);
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] "
"Incorrectly predicted call: [sn:%llu,PC:%#x] "
" Push return address %s onto RAS\n", tid,
squashed_sn, hist_it->seqNum, hist_it->pc,
squashed_sn, hist->seqNum, hist->pc,
*return_addr);
ras->push(tid, *return_addr, hist_it->rasHistory);
ras->push(tid, *return_addr, hist->rasHistory);
}
// The branch was not taken but the RAS modified.
} else if (!actually_taken && (hist_it->rasHistory != nullptr)) {
} else if (!actually_taken && (hist->rasHistory != nullptr)) {
// The branch was not taken but the RAS was modified.
// Needs to be fixed.
ras->squash(tid, hist_it->rasHistory);
ras->squash(tid, hist->rasHistory);
}
}
// Correct BTB ---------------------------------------------------
// Check if the misprediction happened was because of a BTB miss
// or incorrect indirect predictor
if (actually_taken) {
if (hist_it->wasIndirect) {
if (hist->inst->isIndirectCtrl() && !hist->inst->isReturn()) {
++stats.indirectMispredicted;
} else {
DPRINTF(Branch,"[tid:%i] [squash sn:%llu] "
"BTB Update called for [sn:%llu] "
"PC %#x\n", tid, squashed_sn,
hist_it->seqNum, hist_it->pc);
++stats.BTBUpdates;
btb->update(tid, hist_it->pc, corr_target,
getBranchType(hist_it->inst));
btb->update(tid, hist->pc, corr_target,
getBranchType(hist->inst));
++stats.BTBMispredicted;
if (hist->condPred)
++stats.predTakenBTBMiss;
btb->incorrectTarget(hist->pc, hist->type);
DPRINTF(Branch,"[tid:%i] [squash sn:%llu] "
"BTB miss PC %#x %s \n", tid, squashed_sn,
hist->pc, toString(hist->type));
}
}
} else {
DPRINTF(Branch, "[tid:%i] [sn:%llu] pred_hist empty, can't "
"update\n", tid, squashed_sn);
}
}
void
BPredUnit::dump()
{
int i = 0;
for (const auto& ph : predHist) {
if (!ph.empty()) {
auto pred_hist_it = ph.begin();
auto hist = ph.begin();
cprintf("predHist[%i].size(): %i\n", i++, ph.size());
while (pred_hist_it != ph.end()) {
while (hist != ph.end()) {
cprintf("sn:%llu], 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++;
"bpHistory:%#x, rasHistory:%#x\n",
(*hist)->seqNum, (*hist)->pc,
(*hist)->tid, (*hist)->predTaken,
(*hist)->bpHistory, (*hist)->rasHistory);
hist++;
}
cprintf("\n");
@@ -519,5 +615,108 @@ BPredUnit::dump()
}
}
BPredUnit::BPredUnitStats::BPredUnitStats(BPredUnit *bp)
: statistics::Group(bp),
ADD_STAT(lookups, statistics::units::Count::get(),
"Number of BP lookups"),
ADD_STAT(squashes, statistics::units::Count::get(),
"Number of branches that got squashed (completely removed) as "
"an earlier branch was mispredicted."),
ADD_STAT(corrected, statistics::units::Count::get(),
"Number of branches that got corrected but not yet commited. "
"Branches get corrected by decode or after execute. Also a "
"branch misprediction can be detected out-of-order. Therefore, "
"a corrected branch might not end up beeing committed in case "
"an even earlier branch was mispredicted"),
ADD_STAT(earlyResteers, statistics::units::Count::get(),
"Number of branches that got redirected after decode."),
ADD_STAT(committed, statistics::units::Count::get(),
"Number of branches finally committed "),
ADD_STAT(mispredicted, statistics::units::Count::get(),
"Number of committed branches that were mispredicted."),
ADD_STAT(targetProvider, statistics::units::Count::get(),
"The component providing the target for taken branches"),
ADD_STAT(targetWrong, statistics::units::Count::get(),
"Number of branches where the target was incorrect or not "
"available at prediction time."),
ADD_STAT(condPredicted, statistics::units::Count::get(),
"Number of conditional branches predicted"),
ADD_STAT(condPredictedTaken, statistics::units::Count::get(),
"Number of conditional branches predicted as taken"),
ADD_STAT(condIncorrect, statistics::units::Count::get(),
"Number of conditional branches incorrect"),
ADD_STAT(predTakenBTBMiss, statistics::units::Count::get(),
"Number of branches predicted taken but missed in BTB"),
ADD_STAT(NotTakenMispredicted, statistics::units::Count::get(),
"Number branches predicted 'not taken' but turned out "
"to be taken"),
ADD_STAT(TakenMispredicted, statistics::units::Count::get(),
"Number branches predicted taken but are actually not taken"),
ADD_STAT(BTBLookups, statistics::units::Count::get(),
"Number of BTB lookups"),
ADD_STAT(BTBUpdates, statistics::units::Count::get(),
"Number of BTB updates"),
ADD_STAT(BTBHits, statistics::units::Count::get(),
"Number of BTB hits"),
ADD_STAT(BTBHitRatio, statistics::units::Ratio::get(), "BTB Hit Ratio",
BTBHits / BTBLookups),
ADD_STAT(BTBMispredicted, statistics::units::Count::get(),
"Number BTB mispredictions. No target found or target wrong"),
ADD_STAT(indirectLookups, statistics::units::Count::get(),
"Number of indirect predictor lookups."),
ADD_STAT(indirectHits, statistics::units::Count::get(),
"Number of indirect target hits."),
ADD_STAT(indirectMisses, statistics::units::Count::get(),
"Number of indirect misses."),
ADD_STAT(indirectMispredicted, statistics::units::Count::get(),
"Number of mispredicted indirect branches.")
{
using namespace statistics;
BTBHitRatio.precision(6);
lookups
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
lookups.ysubnames(enums::BranchTypeStrings);
squashes
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
squashes.ysubnames(enums::BranchTypeStrings);
corrected
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
corrected.ysubnames(enums::BranchTypeStrings);
earlyResteers
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
earlyResteers.ysubnames(enums::BranchTypeStrings);
committed
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
committed.ysubnames(enums::BranchTypeStrings);
mispredicted
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
mispredicted.ysubnames(enums::BranchTypeStrings);
targetProvider
.init(bp->numThreads, enums::Num_TargetProvider)
.flags(total | pdf);
targetProvider.ysubnames(enums::TargetProviderStrings);
targetWrong
.init(bp->numThreads, enums::Num_BranchType)
.flags(total | pdf);
targetWrong.ysubnames(enums::BranchTypeStrings);
}
} // namespace branch_prediction
} // namespace gem5

View File

@@ -46,12 +46,13 @@
#include "base/statistics.hh"
#include "base/types.hh"
#include "cpu/inst_seq.hh"
#include "cpu/pred/branch_type.hh"
#include "cpu/pred/btb.hh"
#include "cpu/pred/indirect.hh"
#include "cpu/pred/ras.hh"
#include "cpu/inst_seq.hh"
#include "cpu/static_inst.hh"
#include "enums/TargetProvider.hh"
#include "params/BranchPredictor.hh"
#include "sim/probe/pmu.hh"
#include "sim/sim_object.hh"
@@ -68,8 +69,14 @@ namespace branch_prediction
*/
class BPredUnit : public SimObject
{
typedef BranchPredictorParams Params;
typedef enums::TargetProvider TargetProvider;
/** Branch Predictor Unit (BPU) interface functions */
public:
typedef BranchPredictorParams Params;
/**
* @param params The params object, that has the size of the BP and BTB.
*/
@@ -91,9 +98,6 @@ class BPredUnit : public SimObject
bool predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
PCStateBase &pc, ThreadID tid);
// @todo: Rename this function.
virtual void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) = 0;
/**
* Tells the branch predictor to commit any updates until the given
* sequence number.
@@ -118,38 +122,75 @@ class BPredUnit : public SimObject
* @param corr_target The correct branch target.
* @param actually_taken The correct branch direction.
* @param tid The thread id.
* @param from_commit Indicate whether the squash is comming from commit
* or from decode. Its optional and used for statistics.
*/
void squash(const InstSeqNum &squashed_sn,
const PCStateBase &corr_target,
bool actually_taken, ThreadID tid);
void squash(const InstSeqNum &squashed_sn, const PCStateBase &corr_target,
bool actually_taken, ThreadID tid, bool from_commit=true);
protected:
/** *******************************************************
* Interface functions to the conditional branch predictor
*
*/
/**
* @param bp_history Pointer to the history object. The predictor
* will need to update any state and delete the object.
*/
virtual void squash(ThreadID tid, void *bp_history) = 0;
/**
* Looks up a given PC in the BP to see if it is taken or not taken.
* @param inst_PC The PC to look up.
* Looks up a given conditional branch PC of in the BP to see if it
* is taken or not taken.
* @param pc The PC to look up.
* @param bp_history Pointer that will be set to an object that
* has the branch predictor state associated with the lookup.
* @return Whether the branch is taken or not taken.
*/
virtual bool lookup(ThreadID tid, Addr instPC, void * &bp_history) = 0;
virtual bool lookup(ThreadID tid, Addr pc, void * &bp_history) = 0;
/**
* If a branch is not taken, because the BTB address is invalid or missing,
* this function sets the appropriate counter in the global and local
* predictors to not taken.
* @param inst_PC The PC to look up the local predictor.
/**
* Ones done with the prediction this function updates the
* path and global history. All branches call this function
* including unconditional once.
* @param tid The thread id.
* @param PC The branch's PC that will be updated.
* @param uncond Wheather or not this branch is an unconditional branch.
* @param taken Whether or not the branch was taken
* @param target The final target of branch. Some modern
* predictors use the target in their history.
* @param bp_history Pointer that will be set to an object that
* has the branch predictor state associated with the lookup.
*/
virtual void btbUpdate(ThreadID tid, Addr instPC, void * &bp_history) = 0;
virtual void updateHistories(ThreadID tid, Addr pc, bool uncond,
bool taken, Addr target, void * &bp_history) = 0;
/**
* @param tid The thread id.
* @param bp_history Pointer to the history object. The predictor
* will need to update any state and delete the object.
*/
virtual void squash(ThreadID tid, void * &bp_history) = 0;
/**
* Updates the BP with taken/not taken information.
* @param tid The thread id.
* @param PC The branch's PC that will be updated.
* @param taken Whether the branch was taken or not taken.
* @param bp_history Pointer to the branch predictor state that is
* associated with the branch lookup that is being updated.
* @param squashed Set to true when this function is called during a
* squash operation.
* @param inst Static instruction information
* @param target The resolved target of the branch (only needed
* for squashed branches)
* @todo Make this update flexible enough to handle a global predictor.
*/
virtual void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr &inst, Addr target) = 0;
/**
* Looks up a given PC in the BTB to see if a matching entry exists.
* @param tid The thread id.
* @param inst_PC The PC to look up.
* @return Whether the BTB contains the given PC.
*/
@@ -157,15 +198,12 @@ class BPredUnit : public SimObject
{
return btb->valid(tid, instPC);
}
bool BTBValid(ThreadID tid, PCStateBase &instPC)
{
return BTBValid(tid, instPC.instAddr());
}
/**
* Looks up a given PC in the BTB to get the predicted target. The PC may
* be changed or deleted in the future, so it needs to be used immediately,
* and/or copied for use later.
* @param tid The thread id.
* @param inst_PC The PC to look up.
* @return The address of the target of the branch.
*/
@@ -176,21 +214,21 @@ class BPredUnit : public SimObject
}
/**
* Updates the BP with taken/not taken information.
* @param inst_PC The branch's PC that will be updated.
* @param taken Whether the branch was taken or not taken.
* @param bp_history Pointer to the branch predictor state that is
* associated with the branch lookup that is being updated.
* @param squashed Set to true when this function is called during a
* squash operation.
* @param inst Static instruction information
* @param corrTarget The resolved target of the branch (only needed
* for squashed branches)
* @todo Make this update flexible enough to handle a global predictor.
* Looks up a given PC in the BTB to get current static instruction
* information. This is necessary in a decoupled frontend as
* the information does not usually exist at that this point.
* Only for instructions (branches) that hit in the BTB this information
* is available as the BTB stores them together with the target.
*
* @param inst_PC The PC to look up.
* @return The static instruction info of the given PC if existant.
*/
virtual void update(ThreadID tid, Addr instPC, bool taken,
void *bp_history, bool squashed,
const StaticInstPtr &inst, Addr corrTarget) = 0;
const StaticInstPtr
BTBGetInst(ThreadID tid, Addr instPC)
{
return btb->getInst(tid, instPC);
}
/**
* Updates the BTB with the target of a branch.
* @param inst_PC The branch's PC that will be updated.
@@ -213,28 +251,28 @@ class BPredUnit : public SimObject
* Makes a predictor history struct that contains any
* information needed to update the predictor, BTB, and RAS.
*/
PredictorHistory(const InstSeqNum &seq_num, Addr instPC,
bool pred_taken, void *bp_history,
void *indirect_history, ThreadID _tid,
PredictorHistory(ThreadID _tid, InstSeqNum sn, Addr _pc,
const StaticInstPtr & inst)
: seqNum(seq_num), pc(instPC), bpHistory(bp_history),
indirectHistory(indirect_history), rasHistory(nullptr),
tid(_tid),
predTaken(pred_taken), inst(inst)
{}
: seqNum(sn), tid(_tid), pc(_pc),
inst(inst), type(getBranchType(inst)),
call(inst->isCall()), uncond(inst->isUncondCtrl()),
predTaken(false), actuallyTaken(false), condPred(false),
btbHit(false), targetProvider(TargetProvider::NoTarget),
resteered(false), mispredict(false), target(nullptr),
bpHistory(nullptr),
indirectHistory(nullptr), rasHistory(nullptr)
{ }
PredictorHistory(const PredictorHistory &other) :
seqNum(other.seqNum), pc(other.pc), bpHistory(other.bpHistory),
indirectHistory(other.indirectHistory),
rasHistory(other.rasHistory), RASIndex(other.RASIndex),
tid(other.tid), predTaken(other.predTaken), usedRAS(other.usedRAS),
pushedRAS(other.pushedRAS), wasIndirect(other.wasIndirect),
target(other.target), inst(other.inst),
mispredict(other.mispredict)
~PredictorHistory()
{
set(RASTarget, other.RASTarget);
assert(bpHistory == nullptr);
assert(indirectHistory == nullptr);
assert(rasHistory == nullptr);
}
PredictorHistory (const PredictorHistory&) = delete;
PredictorHistory& operator= (const PredictorHistory&) = delete;
bool
operator==(const PredictorHistory &entry) const
{
@@ -242,14 +280,55 @@ class BPredUnit : public SimObject
}
/** The sequence number for the predictor history entry. */
InstSeqNum seqNum;
const InstSeqNum seqNum;
/** The thread id. */
const ThreadID tid;
/** The PC associated with the sequence number. */
Addr pc;
const Addr pc;
/** Pointer to the history object passed back from the branch
* predictor. It is used to update or restore state of the
* branch predictor.
/** The branch instrction */
const StaticInstPtr inst;
/** The type of the branch */
const BranchType type;
/** Whether or not the instruction was a call. */
const bool call;
/** Was unconditional control */
const bool uncond;
/** Whether or not it was predicted taken. */
bool predTaken;
/** To record the actual outcome of the branch */
bool actuallyTaken;
/** The prediction of the conditional predictor */
bool condPred;
/** Was BTB hit at prediction time */
bool btbHit;
/** Which component provided the target */
TargetProvider targetProvider;
/** Resteered */
bool resteered;
/** The branch was corrected hence was mispredicted. */
bool mispredict;
/** The predicted target */
std::unique_ptr<PCStateBase> target;
/**
* Pointer to the history objects passed back from the branch
* predictor subcomponents.
* It is used to update or restore state.
* Respectively for conditional, indirect and RAS.
*/
void *bpHistory = nullptr;
@@ -257,44 +336,40 @@ class BPredUnit : public SimObject
void *rasHistory = nullptr;
/** The RAS target (only valid if a return). */
std::unique_ptr<PCStateBase> RASTarget;
/** The RAS index of the instruction (only valid if a call). */
unsigned RASIndex = 0;
/** The thread id. */
ThreadID tid;
/** Whether or not it was predicted taken. */
bool predTaken;
/** Whether or not the RAS was used. */
bool usedRAS = false;
/* Whether or not the RAS was pushed */
bool pushedRAS = false;
/** Wether this instruction was an indirect branch */
bool wasIndirect = false;
/** Target of the branch. First it is predicted, and fixed later
* if necessary
*/
Addr target = MaxAddr;
/** The branch instrction */
const StaticInstPtr inst;
/** Whether this branch was mispredicted */
bool mispredict = false;
};
typedef std::deque<PredictorHistory> History;
typedef std::deque<PredictorHistory*> History;
/**
* Internal prediction function.
*/
bool predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
PCStateBase &pc, ThreadID tid, PredictorHistory* &bpu_history);
/**
* Squashes a particular branch instance
* @param tid The thread id.
* @param bpu_history The history to be squashed.
*/
void squashHistory(ThreadID tid, PredictorHistory* &bpu_history);
/**
* Commit a particular branch
* @param tid The thread id.
* @param bpu_history The history of the branch to be commited.
*/
void commitBranch(ThreadID tid, PredictorHistory* &bpu_history);
protected:
/** Number of the threads for which the branch history is maintained. */
const unsigned numThreads;
/** Number of bits to shift instructions by for predictor addresses. */
const unsigned instShiftAmt;
/**
* The per-thread predictor history. This is used to update the predictor
@@ -312,42 +387,47 @@ class BPredUnit : public SimObject
/** The indirect target predictor. */
IndirectPredictor * iPred;
/** Statistics */
struct BPredUnitStats : public statistics::Group
{
BPredUnitStats(statistics::Group *parent);
BPredUnitStats(BPredUnit *bp);
/** Stat for number of BP lookups. */
statistics::Scalar lookups;
/** Stat for number of conditional branches predicted. */
/** Stats per branch type */
statistics::Vector2d lookups;
statistics::Vector2d squashes;
statistics::Vector2d corrected;
statistics::Vector2d earlyResteers;
statistics::Vector2d committed;
statistics::Vector2d mispredicted;
/** Target prediction per branch type */
statistics::Vector2d targetProvider;
statistics::Vector2d targetWrong;
/** Additional scalar stats for conditional branches */
statistics::Scalar condPredicted;
/** Stat for number of conditional branches predicted incorrectly. */
statistics::Scalar condPredictedTaken;
statistics::Scalar condIncorrect;
/** Stat for number of BTB lookups. */
statistics::Scalar BTBLookups;
/** Stat for number of BTB updates. */
statistics::Scalar BTBUpdates;
/** Stat for number of BTB hits. */
statistics::Scalar BTBHits;
/** Stat for the ratio between BTB hits and BTB lookups. */
statistics::Formula BTBHitRatio;
/** Stat for number of times the RAS is used to get a target. */
statistics::Scalar RASUsed;
/** Stat for number of times the RAS is incorrect. */
statistics::Scalar RASIncorrect;
statistics::Scalar predTakenBTBMiss;
statistics::Scalar NotTakenMispredicted;
statistics::Scalar TakenMispredicted;
/** Stat for the number of indirect target lookups.*/
/** BTB stats. */
statistics::Scalar BTBLookups;
statistics::Scalar BTBUpdates;
statistics::Scalar BTBHits;
statistics::Formula BTBHitRatio;
statistics::Scalar BTBMispredicted;
/** Indirect stats */
statistics::Scalar indirectLookups;
/** Stat for the number of indirect target hits.*/
statistics::Scalar indirectHits;
/** Stat for the number of indirect target misses.*/
statistics::Scalar indirectMisses;
/** Stat for the number of indirect target mispredictions.*/
statistics::Scalar indirectMispredicted;
} stats;
protected:
/** Number of bits to shift instructions by for predictor addresses. */
const unsigned instShiftAmt;
/**
* @{

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The University of Wisconsin
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
@@ -320,10 +332,13 @@ LoopPredictor::squashLoop(BranchInfo* bi)
void
LoopPredictor::updateStats(bool taken, BranchInfo* bi)
{
if (taken == bi->loopPred) {
stats.correct++;
} else {
stats.wrong++;
if (bi->loopPredUsed) {
stats.used++;
if (taken == bi->loopPred) {
stats.correct++;
} else {
stats.wrong++;
}
}
}
@@ -354,6 +369,8 @@ LoopPredictor::condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
LoopPredictor::LoopPredictorStats::LoopPredictorStats(
statistics::Group *parent)
: statistics::Group(parent),
ADD_STAT(used, statistics::units::Count::get(),
"Number of times the loop predictor is the provider."),
ADD_STAT(correct, statistics::units::Count::get(),
"Number of times the loop predictor is the provider and the "
"prediction is correct"),

View File

@@ -1,5 +1,15 @@
/*
* Copyright (c) 2014 The University of Wisconsin
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
* Informatique et en Automatique / French National Research Institute
@@ -92,6 +102,7 @@ class LoopPredictor : public SimObject
struct LoopPredictorStats : public statistics::Group
{
LoopPredictorStats(statistics::Group *parent);
statistics::Scalar used;
statistics::Scalar correct;
statistics::Scalar wrong;
} stats;

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The University of Wisconsin
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
@@ -94,8 +106,8 @@ LTAGE::predict(ThreadID tid, Addr branch_pc, bool cond_branch, void* &b)
// PREDICTOR UPDATE
void
LTAGE::update(ThreadID tid, Addr branch_pc, bool taken, void* bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget)
LTAGE::update(ThreadID tid, Addr pc, bool taken, void * &bp_history,
bool squashed, const StaticInstPtr & inst, Addr target)
{
assert(bp_history);
@@ -105,7 +117,7 @@ LTAGE::update(ThreadID tid, Addr branch_pc, bool taken, void* bp_history,
if (tage->isSpeculativeUpdateEnabled()) {
// This restores the global history, then update it
// and recomputes the folded histories.
tage->squash(tid, taken, bi->tageBranchInfo, corrTarget);
tage->squash(tid, taken, bi->tageBranchInfo, target);
if (bi->tageBranchInfo->condBranch) {
loopPredictor->squashLoop(bi->lpBranchInfo);
@@ -117,26 +129,27 @@ LTAGE::update(ThreadID tid, Addr branch_pc, bool taken, void* bp_history,
int nrand = random_mt.random<int>() & 3;
if (bi->tageBranchInfo->condBranch) {
DPRINTF(LTage, "Updating tables for branch:%lx; taken?:%d\n",
branch_pc, taken);
pc, taken);
tage->updateStats(taken, bi->tageBranchInfo);
loopPredictor->updateStats(taken, bi->lpBranchInfo);
loopPredictor->condBranchUpdate(tid, branch_pc, taken,
loopPredictor->condBranchUpdate(tid, pc, taken,
bi->tageBranchInfo->tagePred, bi->lpBranchInfo, instShiftAmt);
tage->condBranchUpdate(tid, branch_pc, taken, bi->tageBranchInfo,
nrand, corrTarget, bi->lpBranchInfo->predTaken);
tage->condBranchUpdate(tid, pc, taken, bi->tageBranchInfo,
nrand, target, bi->lpBranchInfo->predTaken);
}
tage->updateHistories(tid, branch_pc, taken, bi->tageBranchInfo, false,
inst, corrTarget);
tage->updateHistories(tid, pc, taken, bi->tageBranchInfo, false,
inst, target);
delete bi;
bp_history = nullptr;
}
void
LTAGE::squash(ThreadID tid, void *bp_history)
LTAGE::squash(ThreadID tid, void * &bp_history)
{
LTageBranchInfo* bi = (LTageBranchInfo*)(bp_history);

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The University of Wisconsin
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
@@ -69,10 +81,10 @@ class LTAGE : public TAGE
LTAGE(const LTAGEParams &params);
// Base class methods.
void squash(ThreadID tid, void *bp_history) override;
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst,
Addr corrTarget) override;
void squash(ThreadID tid, void * &bp_history) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
void init() override;
@@ -98,6 +110,7 @@ class LTAGE : public TAGE
virtual ~LTageBranchInfo()
{
delete lpBranchInfo;
lpBranchInfo = nullptr;
}
};

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright 2019 Texas A&M University
*
* Redistribution and use in source and binary forms, with or without
@@ -547,10 +559,19 @@ MultiperspectivePerceptron::train(ThreadID tid, MPPBranchInfo &bi, bool taken)
}
}
void
MultiperspectivePerceptron::uncondBranch(ThreadID tid, Addr pc,
void * &bp_history)
MultiperspectivePerceptron::updateHistories(ThreadID tid, Addr pc,
bool uncond, bool taken, Addr target, void * &bp_history)
{
assert(uncond || bp_history);
// For perceptron there is no speculative history correction.
// Conditional branches are done.
if (!uncond)
return;
// For uncondition branches create branch info.
MPPBranchInfo *bi = new MPPBranchInfo(pc, pcshift, false);
std::vector<unsigned int> &ghist_words = threadData[tid]->ghist_words;
@@ -613,10 +634,10 @@ MultiperspectivePerceptron::lookup(ThreadID tid, Addr instPC,
}
void
MultiperspectivePerceptron::update(ThreadID tid, Addr instPC, bool taken,
void *bp_history, bool squashed,
MultiperspectivePerceptron::update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst,
Addr corrTarget)
Addr target)
{
assert(bp_history);
MPPBranchInfo *bi = static_cast<MPPBranchInfo*>(bp_history);
@@ -627,6 +648,7 @@ MultiperspectivePerceptron::update(ThreadID tid, Addr instPC, bool taken,
if (bi->isUnconditional()) {
delete bi;
bp_history = nullptr;
return;
}
@@ -693,7 +715,6 @@ MultiperspectivePerceptron::update(ThreadID tid, Addr instPC, bool taken,
// four different styles of IMLI
if (!bi->filtered || (record_mask & Imli)) {
unsigned int target = corrTarget;
if (target < bi->getPC()) {
if (taken) {
threadData[tid]->imli_counter[0] += 1;
@@ -813,20 +834,16 @@ MultiperspectivePerceptron::update(ThreadID tid, Addr instPC, bool taken,
threadData[tid]->last_ghist_bit = taken;
delete bi;
bp_history = nullptr;
}
void
MultiperspectivePerceptron::btbUpdate(ThreadID tid, Addr branch_pc,
void* &bp_history)
{
}
void
MultiperspectivePerceptron::squash(ThreadID tid, void *bp_history)
MultiperspectivePerceptron::squash(ThreadID tid, void * &bp_history)
{
assert(bp_history);
MPPBranchInfo *bi = static_cast<MPPBranchInfo*>(bp_history);
delete bi;
bp_history = nullptr;
}
} // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright 2019 Texas A&M University
*
* Redistribution and use in source and binary forms, with or without
@@ -1048,14 +1060,14 @@ class MultiperspectivePerceptron : public BPredUnit
void init() override;
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) override;
void squash(ThreadID tid, void *bp_history) override;
bool lookup(ThreadID tid, Addr instPC, void * &bp_history) override;
void update(ThreadID tid, Addr instPC, bool taken,
void *bp_history, bool squashed,
const StaticInstPtr & inst,
Addr corrTarget) override;
void btbUpdate(ThreadID tid, Addr branch_addr, void* &bp_history) override;
// Base class methods.
bool lookup(ThreadID tid, Addr branch_addr, void* &bp_history) override;
void updateHistories(ThreadID tid, Addr pc, bool uncond, bool taken,
Addr target, void * &bp_history) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
void squash(ThreadID tid, void * &bp_history) override;
};
} // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright 2019 Texas A&M University
*
* Redistribution and use in source and binary forms, with or without
@@ -548,7 +560,7 @@ MultiperspectivePerceptronTAGE::lookup(ThreadID tid, Addr instPC,
void
MPP_StatisticalCorrector::condBranchUpdate(ThreadID tid, Addr branch_pc,
bool taken, StatisticalCorrector::BranchInfo *bi, Addr corrTarget,
bool taken, StatisticalCorrector::BranchInfo *bi, Addr target,
bool bias_bit, int hitBank, int altBank, int64_t phist)
{
bool scPred = (bi->lsum >= 0);
@@ -588,10 +600,10 @@ MPP_StatisticalCorrector::condBranchUpdate(ThreadID tid, Addr branch_pc,
}
void
MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
void *bp_history, bool squashed,
MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst,
Addr corrTarget)
Addr target)
{
assert(bp_history);
MPPTAGEBranchInfo *bi = static_cast<MPPTAGEBranchInfo*>(bp_history);
@@ -600,7 +612,7 @@ MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
if (tage->isSpeculativeUpdateEnabled()) {
// This restores the global history, then update it
// and recomputes the folded histories.
tage->squash(tid, taken, bi->tageBranchInfo, corrTarget);
tage->squash(tid, taken, bi->tageBranchInfo, target);
if (bi->tageBranchInfo->condBranch) {
loopPredictor->squashLoop(bi->lpBranchInfo);
}
@@ -609,16 +621,16 @@ MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
}
if (bi->isUnconditional()) {
statisticalCorrector->scHistoryUpdate(instPC, inst, taken,
bi->scBranchInfo, corrTarget);
tage->updateHistories(tid, instPC, taken, bi->tageBranchInfo, false,
inst, corrTarget);
statisticalCorrector->scHistoryUpdate(pc, inst, taken,
bi->scBranchInfo, target);
tage->updateHistories(tid, pc, taken, bi->tageBranchInfo, false,
inst, target);
} else {
tage->updateStats(taken, bi->tageBranchInfo);
loopPredictor->updateStats(taken, bi->lpBranchInfo);
statisticalCorrector->updateStats(taken, bi->scBranchInfo);
loopPredictor->condBranchUpdate(tid, instPC, taken,
loopPredictor->condBranchUpdate(tid, pc, taken,
bi->tageBranchInfo->tagePred, bi->lpBranchInfo, instShiftAmt);
bool scPred = (bi->scBranchInfo->lsum >= 0);
@@ -626,13 +638,13 @@ MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
((abs(bi->scBranchInfo->lsum) < bi->scBranchInfo->thres))) {
updatePartial(tid, *bi, taken);
}
statisticalCorrector->condBranchUpdate(tid, instPC, taken,
bi->scBranchInfo, corrTarget, false /* bias_bit: unused */,
statisticalCorrector->condBranchUpdate(tid, pc, taken,
bi->scBranchInfo, target, false /* bias_bit: unused */,
0 /* hitBank: unused */, 0 /* altBank: unused*/,
tage->getPathHist(tid));
tage->condBranchUpdate(tid, instPC, taken, bi->tageBranchInfo,
random_mt.random<int>(), corrTarget,
tage->condBranchUpdate(tid, pc, taken, bi->tageBranchInfo,
random_mt.random<int>(), target,
bi->predictedTaken, true);
updateHistories(tid, *bi, taken);
@@ -640,8 +652,8 @@ MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
if (!tage->isSpeculativeUpdateEnabled()) {
if (inst->isCondCtrl() && inst->isDirectCtrl()
&& !inst->isCall() && !inst->isReturn()) {
uint32_t truncated_target = corrTarget;
uint32_t truncated_pc = instPC;
uint32_t truncated_target = target;
uint32_t truncated_pc = pc;
if (truncated_target < truncated_pc) {
if (!taken) {
threadData[tid]->imli_counter[0] = 0;
@@ -657,20 +669,28 @@ MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
}
}
statisticalCorrector->scHistoryUpdate(instPC, inst, taken,
bi->scBranchInfo, corrTarget);
statisticalCorrector->scHistoryUpdate(pc, inst, taken,
bi->scBranchInfo, target);
tage->updateHistories(tid, instPC, taken, bi->tageBranchInfo,
false, inst, corrTarget);
tage->updateHistories(tid, pc, taken, bi->tageBranchInfo,
false, inst, target);
}
}
delete bi;
bp_history = nullptr;
}
void
MultiperspectivePerceptronTAGE::uncondBranch(ThreadID tid, Addr pc,
void * &bp_history)
MultiperspectivePerceptronTAGE::updateHistories(ThreadID tid, Addr pc,
bool uncond, bool taken,
Addr target, void * &bp_history)
{
assert(uncond || bp_history);
// For perceptron there is no speculative history correction.
// Conditional branches are done.
if (!uncond) return;
MPPTAGEBranchInfo *bi =
new MPPTAGEBranchInfo(pc, pcshift, false, *tage, *loopPredictor,
*statisticalCorrector);
@@ -678,11 +698,12 @@ MultiperspectivePerceptronTAGE::uncondBranch(ThreadID tid, Addr pc,
}
void
MultiperspectivePerceptronTAGE::squash(ThreadID tid, void *bp_history)
MultiperspectivePerceptronTAGE::squash(ThreadID tid, void * &bp_history)
{
assert(bp_history);
MPPTAGEBranchInfo *bi = static_cast<MPPTAGEBranchInfo*>(bp_history);
delete bi;
bp_history = nullptr;
}
} // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright 2019 Texas A&M University
*
* Redistribution and use in source and binary forms, with or without
@@ -178,7 +190,7 @@ class MPP_StatisticalCorrector : public StatisticalCorrector
void condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
StatisticalCorrector::BranchInfo *bi,
Addr corrTarget, bool b, int hitBank, int altBank,
Addr target, bool b, int hitBank, int altBank,
int64_t phist) override;
virtual void getBiasLSUM(Addr branch_pc,
@@ -236,12 +248,12 @@ class MultiperspectivePerceptronTAGE : public MultiperspectivePerceptron
bool lookup(ThreadID tid, Addr instPC, void * &bp_history) override;
void update(ThreadID tid, Addr instPC, bool taken,
void *bp_history, bool squashed,
const StaticInstPtr & inst,
Addr corrTarget) override;
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) override;
void squash(ThreadID tid, void *bp_history) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
void updateHistories(ThreadID tid, Addr pc, bool uncond, bool taken,
Addr target, void * &bp_history) override;
void squash(ThreadID tid, void * &bp_history) override;
};

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The University of Wisconsin
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
@@ -56,8 +68,8 @@ TAGE::TAGE(const TAGEParams &params) : BPredUnit(params), tage(params.tage)
// PREDICTOR UPDATE
void
TAGE::update(ThreadID tid, Addr branch_pc, bool taken, void* bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget)
TAGE::update(ThreadID tid, Addr pc, bool taken, void * &bp_history,
bool squashed, const StaticInstPtr & inst, Addr target)
{
assert(bp_history);
@@ -67,69 +79,65 @@ TAGE::update(ThreadID tid, Addr branch_pc, bool taken, void* bp_history,
if (squashed) {
// This restores the global history, then update it
// and recomputes the folded histories.
tage->squash(tid, taken, tage_bi, corrTarget);
tage->squash(tid, taken, tage_bi, target);
return;
}
int nrand = random_mt.random<int>() & 3;
if (bi->tageBranchInfo->condBranch) {
DPRINTF(Tage, "Updating tables for branch:%lx; taken?:%d\n",
branch_pc, taken);
pc, taken);
tage->updateStats(taken, bi->tageBranchInfo);
tage->condBranchUpdate(tid, branch_pc, taken, tage_bi, nrand,
corrTarget, bi->tageBranchInfo->tagePred);
tage->condBranchUpdate(tid, pc, taken, tage_bi, nrand,
target, bi->tageBranchInfo->tagePred);
}
// optional non speculative update of the histories
tage->updateHistories(tid, branch_pc, taken, tage_bi, false, inst,
corrTarget);
tage->updateHistories(tid, pc, taken, tage_bi, false, inst, target);
delete bi;
bp_history = nullptr;
}
void
TAGE::squash(ThreadID tid, void *bp_history)
TAGE::squash(ThreadID tid, void * &bp_history)
{
TageBranchInfo *bi = static_cast<TageBranchInfo*>(bp_history);
DPRINTF(Tage, "Deleting branch info: %lx\n", bi->tageBranchInfo->branchPC);
delete bi;
bp_history = nullptr;
}
bool
TAGE::predict(ThreadID tid, Addr branch_pc, bool cond_branch, void* &b)
TAGE::predict(ThreadID tid, Addr pc, bool cond_branch, void* &b)
{
TageBranchInfo *bi = new TageBranchInfo(*tage);//nHistoryTables+1);
b = (void*)(bi);
return tage->tagePredict(tid, branch_pc, cond_branch, bi->tageBranchInfo);
return tage->tagePredict(tid, pc, cond_branch, bi->tageBranchInfo);
}
bool
TAGE::lookup(ThreadID tid, Addr branch_pc, void* &bp_history)
TAGE::lookup(ThreadID tid, Addr pc, void* &bp_history)
{
bool retval = predict(tid, branch_pc, true, bp_history);
bool retval = predict(tid, pc, true, bp_history);
TageBranchInfo *bi = static_cast<TageBranchInfo*>(bp_history);
DPRINTF(Tage, "Lookup branch: %lx; predict:%d\n", branch_pc, retval);
tage->updateHistories(tid, branch_pc, retval, bi->tageBranchInfo, true);
DPRINTF(Tage, "Lookup branch: %lx; predict:%d\n", pc, retval);
return retval;
}
void
TAGE::btbUpdate(ThreadID tid, Addr branch_pc, void* &bp_history)
TAGE::updateHistories(ThreadID tid, Addr pc, bool uncond,
bool taken, Addr target, void * &bp_history)
{
TageBranchInfo *bi = static_cast<TageBranchInfo*>(bp_history);
tage->btbUpdate(tid, branch_pc, bi->tageBranchInfo);
}
assert(uncond || bp_history);
if (uncond) {
DPRINTF(Tage, "UnConditionalBranch: %lx\n", pc);
predict(tid, pc, false, bp_history);
}
void
TAGE::uncondBranch(ThreadID tid, Addr br_pc, void* &bp_history)
{
DPRINTF(Tage, "UnConditionalBranch: %lx\n", br_pc);
predict(tid, br_pc, false, bp_history);
// Update the global history for all branches
TageBranchInfo *bi = static_cast<TageBranchInfo*>(bp_history);
tage->updateHistories(tid, br_pc, true, bi->tageBranchInfo, true);
tage->updateHistories(tid, pc, taken, bi->tageBranchInfo, true);
}
} // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2014 The University of Wisconsin
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
@@ -87,13 +99,13 @@ class TAGE: public BPredUnit
TAGE(const TAGEParams &params);
// Base class methods.
void uncondBranch(ThreadID tid, Addr br_pc, void* &bp_history) override;
bool lookup(ThreadID tid, Addr branch_addr, void* &bp_history) override;
void btbUpdate(ThreadID tid, Addr branch_addr, void* &bp_history) override;
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst,
Addr corrTarget) override;
virtual void squash(ThreadID tid, void *bp_history) override;
bool lookup(ThreadID tid, Addr pc, void* &bp_history) override;
void updateHistories(ThreadID tid, Addr pc, bool uncond, bool taken,
Addr target, void * &bp_history) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
virtual void squash(ThreadID tid, void * &bp_history) override;
};
} // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
@@ -362,16 +374,16 @@ TAGE_SC_L_TAGE::extraAltCalc(TAGEBase::BranchInfo* bi)
}
bool
TAGE_SC_L::predict(ThreadID tid, Addr branch_pc, bool cond_branch, void* &b)
TAGE_SC_L::predict(ThreadID tid, Addr pc, bool cond_branch, void* &b)
{
TageSCLBranchInfo *bi = new TageSCLBranchInfo(*tage,
*statisticalCorrector,
*loopPredictor);
b = (void*)(bi);
bool pred_taken = tage->tagePredict(tid, branch_pc, cond_branch,
bool pred_taken = tage->tagePredict(tid, pc, cond_branch,
bi->tageBranchInfo);
pred_taken = loopPredictor->loopPredict(tid, branch_pc, cond_branch,
pred_taken = loopPredictor->loopPredict(tid, pc, cond_branch,
bi->lpBranchInfo, pred_taken,
instShiftAmt);
@@ -394,7 +406,7 @@ TAGE_SC_L::predict(ThreadID tid, Addr branch_pc, bool cond_branch, void* &b)
bool bias = (bi->tageBranchInfo->longestMatchPred !=
bi->tageBranchInfo->altTaken);
pred_taken = statisticalCorrector->scPredict(tid, branch_pc, cond_branch,
pred_taken = statisticalCorrector->scPredict(tid, pc, cond_branch,
bi->scBranchInfo, pred_taken, bias, use_tage_ctr, tage_ctr,
tage->getTageCtrBits(), bi->tageBranchInfo->hitBank,
bi->tageBranchInfo->altBank, tage->getPathHist(tid));
@@ -410,8 +422,8 @@ TAGE_SC_L::predict(ThreadID tid, Addr branch_pc, bool cond_branch, void* &b)
}
void
TAGE_SC_L::update(ThreadID tid, Addr branch_pc, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget)
TAGE_SC_L::update(ThreadID tid, Addr pc, bool taken, void *&bp_history,
bool squashed, const StaticInstPtr & inst, Addr target)
{
assert(bp_history);
@@ -423,7 +435,7 @@ TAGE_SC_L::update(ThreadID tid, Addr branch_pc, bool taken, void *bp_history,
if (tage->isSpeculativeUpdateEnabled()) {
// This restores the global history, then update it
// and recomputes the folded histories.
tage->squash(tid, taken, tage_bi, corrTarget);
tage->squash(tid, taken, tage_bi, target);
if (bi->tageBranchInfo->condBranch) {
loopPredictor->squashLoop(bi->lpBranchInfo);
}
@@ -434,7 +446,7 @@ TAGE_SC_L::update(ThreadID tid, Addr branch_pc, bool taken, void *bp_history,
int nrand = random_mt.random<int>() & 3;
if (tage_bi->condBranch) {
DPRINTF(TageSCL, "Updating tables for branch:%lx; taken?:%d\n",
branch_pc, taken);
pc, taken);
tage->updateStats(taken, bi->tageBranchInfo);
loopPredictor->updateStats(taken, bi->lpBranchInfo);
@@ -443,26 +455,27 @@ TAGE_SC_L::update(ThreadID tid, Addr branch_pc, bool taken, void *bp_history,
bool bias = (bi->tageBranchInfo->longestMatchPred !=
bi->tageBranchInfo->altTaken);
statisticalCorrector->condBranchUpdate(tid, branch_pc, taken,
bi->scBranchInfo, corrTarget, bias, bi->tageBranchInfo->hitBank,
statisticalCorrector->condBranchUpdate(tid, pc, taken,
bi->scBranchInfo, target, bias, bi->tageBranchInfo->hitBank,
bi->tageBranchInfo->altBank, tage->getPathHist(tid));
loopPredictor->condBranchUpdate(tid, branch_pc, taken,
loopPredictor->condBranchUpdate(tid, pc, taken,
bi->tageBranchInfo->tagePred, bi->lpBranchInfo, instShiftAmt);
tage->condBranchUpdate(tid, branch_pc, taken, bi->tageBranchInfo,
nrand, corrTarget, bi->lpBranchInfo->predTaken);
tage->condBranchUpdate(tid, pc, taken, bi->tageBranchInfo,
nrand, target, bi->lpBranchInfo->predTaken);
}
if (!tage->isSpeculativeUpdateEnabled()) {
statisticalCorrector->scHistoryUpdate(branch_pc, inst, taken,
bi->scBranchInfo, corrTarget);
statisticalCorrector->scHistoryUpdate(pc, inst, taken,
bi->scBranchInfo, target);
tage->updateHistories(tid, branch_pc, taken, bi->tageBranchInfo, false,
inst, corrTarget);
tage->updateHistories(tid, pc, taken, bi->tageBranchInfo, false,
inst, target);
}
delete bi;
bp_history = nullptr;
}
} // namespace branch_prediction

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
@@ -159,12 +171,11 @@ class TAGE_SC_L: public LTAGE
public:
TAGE_SC_L(const TAGE_SC_LParams &params);
bool predict(
ThreadID tid, Addr branch_pc, bool cond_branch, void* &b) override;
bool predict(ThreadID tid, Addr pc, bool cond_branch, void* &b) override;
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst,
Addr corrTarget) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
protected:

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2011, 2014 ARM Limited
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -134,50 +135,22 @@ TournamentBP::calcLocHistIdx(Addr &branch_addr)
inline
void
TournamentBP::updateGlobalHistTaken(ThreadID tid)
TournamentBP::updateGlobalHist(ThreadID tid, bool taken)
{
globalHistory[tid] = (globalHistory[tid] << 1) | 1;
globalHistory[tid] = (globalHistory[tid] << 1) | taken;
globalHistory[tid] = globalHistory[tid] & historyRegisterMask;
}
inline
void
TournamentBP::updateGlobalHistNotTaken(ThreadID tid)
{
globalHistory[tid] = (globalHistory[tid] << 1);
globalHistory[tid] = globalHistory[tid] & historyRegisterMask;
}
inline
void
TournamentBP::updateLocalHistTaken(unsigned local_history_idx)
TournamentBP::updateLocalHist(unsigned local_history_idx, bool taken)
{
localHistoryTable[local_history_idx] =
(localHistoryTable[local_history_idx] << 1) | 1;
}
inline
void
TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
{
localHistoryTable[local_history_idx] =
(localHistoryTable[local_history_idx] << 1);
}
void
TournamentBP::btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history)
{
unsigned local_history_idx = calcLocHistIdx(branch_addr);
//Update Global History to Not Taken (clear LSB)
globalHistory[tid] &= (historyRegisterMask & ~1ULL);
//Update Local History to Not Taken
localHistoryTable[local_history_idx] =
localHistoryTable[local_history_idx] & (localPredictorMask & ~1ULL);
(localHistoryTable[local_history_idx] << 1) | taken;
}
bool
TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
TournamentBP::lookup(ThreadID tid, Addr pc, void * &bp_history)
{
bool local_prediction;
unsigned local_history_idx;
@@ -187,7 +160,7 @@ TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
bool choice_prediction;
//Lookup in the local predictor to get its branch prediction
local_history_idx = calcLocHistIdx(branch_addr);
local_history_idx = calcLocHistIdx(pc);
local_predictor_idx = localHistoryTable[local_history_idx]
& localPredictorMask;
local_prediction = localCtrs[local_predictor_idx] > localThreshold;
@@ -212,57 +185,53 @@ TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
assert(local_history_idx < localHistoryTableSize);
// Speculative update of the global history and the
// selected local history.
// Select and return the prediction
// History update will be happen in the next function
if (choice_prediction) {
if (global_prediction) {
updateGlobalHistTaken(tid);
updateLocalHistTaken(local_history_idx);
return true;
} else {
updateGlobalHistNotTaken(tid);
updateLocalHistNotTaken(local_history_idx);
return false;
}
return global_prediction;
} else {
if (local_prediction) {
updateGlobalHistTaken(tid);
updateLocalHistTaken(local_history_idx);
return true;
} else {
updateGlobalHistNotTaken(tid);
updateLocalHistNotTaken(local_history_idx);
return false;
}
return local_prediction;
}
}
void
TournamentBP::uncondBranch(ThreadID tid, Addr pc, void * &bp_history)
TournamentBP::updateHistories(ThreadID tid, Addr pc, bool uncond,
bool taken, Addr target, void * &bp_history)
{
// Create BPHistory and pass it back to be recorded.
BPHistory *history = new BPHistory;
history->globalHistory = globalHistory[tid];
history->localPredTaken = true;
history->globalPredTaken = true;
history->globalUsed = true;
history->localHistoryIdx = invalidPredictorIndex;
history->localHistory = invalidPredictorIndex;
bp_history = static_cast<void *>(history);
assert(uncond || bp_history);
if (uncond) {
// Create BPHistory and pass it back to be recorded.
BPHistory *history = new BPHistory;
history->globalHistory = globalHistory[tid];
history->localPredTaken = true;
history->globalPredTaken = true;
history->globalUsed = true;
history->localHistoryIdx = invalidPredictorIndex;
history->localHistory = invalidPredictorIndex;
bp_history = static_cast<void *>(history);
}
updateGlobalHistTaken(tid);
// Update the global history for all branches
updateGlobalHist(tid, taken);
// Update the local history only for conditional branches
if (!uncond) {
auto history = static_cast<BPHistory *>(bp_history);
updateLocalHist(history->localHistoryIdx, taken);
}
}
void
TournamentBP::update(ThreadID tid, Addr branch_addr, bool taken,
void *bp_history, bool squashed,
const StaticInstPtr & inst, Addr corrTarget)
TournamentBP::update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target)
{
assert(bp_history);
BPHistory *history = static_cast<BPHistory *>(bp_history);
unsigned local_history_idx = calcLocHistIdx(branch_addr);
unsigned local_history_idx = calcLocHistIdx(pc);
assert(local_history_idx < localHistoryTableSize);
@@ -330,10 +299,11 @@ TournamentBP::update(ThreadID tid, Addr branch_addr, bool taken,
// We're done with this history, now delete it.
delete history;
bp_history = nullptr;
}
void
TournamentBP::squash(ThreadID tid, void *bp_history)
TournamentBP::squash(ThreadID tid, void * &bp_history)
{
BPHistory *history = static_cast<BPHistory *>(bp_history);
@@ -347,6 +317,7 @@ TournamentBP::squash(ThreadID tid, void *bp_history)
// Delete this BPHistory now that we're done with it.
delete history;
bp_history = nullptr;
}
#ifdef GEM5_DEBUG

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2011, 2014 ARM Limited
* Copyright (c) 2022-2023 The University of Edinburgh
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -70,52 +71,14 @@ class TournamentBP : public BPredUnit
*/
TournamentBP(const TournamentBPParams &params);
/**
* Looks up the given address in the branch predictor and returns
* a true/false value as to whether it is taken. Also creates a
* BPHistory object to store any state it will need on squash/update.
* @param branch_addr The address of the branch to look up.
* @param bp_history Pointer that will be set to the BPHistory object.
* @return Whether or not the branch is taken.
*/
bool lookup(ThreadID tid, Addr branch_addr, void * &bp_history);
/**
* Records that there was an unconditional branch, and modifies
* the bp history to point to an object that has the previous
* global history stored in it.
* @param bp_history Pointer that will be set to the BPHistory object.
*/
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
/**
* Updates the branch predictor to Not Taken if a BTB entry is
* invalid or not found.
* @param branch_addr The address of the branch to look up.
* @param bp_history Pointer to any bp history state.
* @return Whether or not the branch is taken.
*/
void btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history);
/**
* Updates the branch predictor with the actual result of a branch.
* @param branch_addr The address of the branch to update.
* @param taken Whether or not the branch was taken.
* @param bp_history Pointer to the BPHistory object that was created
* when the branch was predicted.
* @param squashed is set when this function is called during a squash
* operation.
* @param inst Static instruction information
* @param corrTarget Resolved target of the branch (only needed if
* squashed)
*/
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
bool squashed, const StaticInstPtr & inst, Addr corrTarget);
/**
* Restores the global branch history on a squash.
* @param bp_history Pointer to the BPHistory object that has the
* previous global branch history in it.
*/
void squash(ThreadID tid, void *bp_history);
// Base class methods.
bool lookup(ThreadID tid, Addr pc, void* &bp_history) override;
void updateHistories(ThreadID tid, Addr pc, bool uncond, bool taken,
Addr target, void * &bp_history) override;
void update(ThreadID tid, Addr pc, bool taken,
void * &bp_history, bool squashed,
const StaticInstPtr & inst, Addr target) override;
void squash(ThreadID tid, void * &bp_history) override;
private:
/**
@@ -131,25 +94,18 @@ class TournamentBP : public BPredUnit
*/
inline unsigned calcLocHistIdx(Addr &branch_addr);
/** Updates global history as taken. */
inline void updateGlobalHistTaken(ThreadID tid);
/** Updates global history as not taken. */
inline void updateGlobalHistNotTaken(ThreadID tid);
/** Updates global history with the given direction
* @param taken Whether or not the branch was taken
*/
inline void updateGlobalHist(ThreadID tid, bool taken);
/**
* Updates local histories as taken.
* Updates local histories.
* @param local_history_idx The local history table entry that
* will be updated.
* @param taken Whether or not the branch was taken.
*/
inline void updateLocalHistTaken(unsigned local_history_idx);
/**
* Updates local histories as not taken.
* @param local_history_idx The local history table entry that
* will be updated.
*/
inline void updateLocalHistNotTaken(unsigned local_history_idx);
inline void updateLocalHist(unsigned local_history_idx, bool taken);
/**
* The branch history information that is created upon predicting