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:
@@ -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 ¶ms)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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 ¶ms);
|
||||
|
||||
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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 ¶ms)
|
||||
* 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
|
||||
|
||||
@@ -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 ¶ms);
|
||||
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
|
||||
{
|
||||
|
||||
@@ -58,45 +58,15 @@ namespace branch_prediction
|
||||
BPredUnit::BPredUnit(const Params ¶ms)
|
||||
: 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* @{
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ¶ms);
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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 ¶ms) : 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
|
||||
|
||||
@@ -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 ¶ms);
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ¶ms);
|
||||
|
||||
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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ¶ms);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
Reference in New Issue
Block a user