From ccbb85c67fbf5ace280763b4e668b098a0ee9b3a Mon Sep 17 00:00:00 2001 From: David Schall Date: Tue, 17 Oct 2023 15:16:54 +0000 Subject: [PATCH] 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 --- src/cpu/pred/2bit_local.cc | 26 +- src/cpu/pred/2bit_local.hh | 35 +- src/cpu/pred/BranchPredictor.py | 9 + src/cpu/pred/SConscript | 2 +- src/cpu/pred/bi_mode.cc | 53 +- src/cpu/pred/bi_mode.hh | 26 +- src/cpu/pred/bpred_unit.cc | 691 +++++++++++------- src/cpu/pred/bpred_unit.hh | 316 +++++--- src/cpu/pred/loop_predictor.cc | 25 +- src/cpu/pred/loop_predictor.hh | 13 +- src/cpu/pred/ltage.cc | 33 +- src/cpu/pred/ltage.hh | 21 +- src/cpu/pred/multiperspective_perceptron.cc | 43 +- src/cpu/pred/multiperspective_perceptron.hh | 28 +- .../pred/multiperspective_perceptron_tage.cc | 67 +- .../pred/multiperspective_perceptron_tage.hh | 26 +- src/cpu/pred/tage.cc | 64 +- src/cpu/pred/tage.hh | 26 +- src/cpu/pred/tage_sc_l.cc | 47 +- src/cpu/pred/tage_sc_l.hh | 21 +- src/cpu/pred/tournament.cc | 111 ++- src/cpu/pred/tournament.hh | 76 +- 22 files changed, 1079 insertions(+), 680 deletions(-) diff --git a/src/cpu/pred/2bit_local.cc b/src/cpu/pred/2bit_local.cc index c9aa714ed1..00baf92882 100644 --- a/src/cpu/pred/2bit_local.cc +++ b/src/cpu/pred/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) 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 diff --git a/src/cpu/pred/2bit_local.hh b/src/cpu/pred/2bit_local.hh index 55f45ca55c..9bdb1131fd 100644 --- a/src/cpu/pred/2bit_local.hh +++ b/src/cpu/pred/2bit_local.hh @@ -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: diff --git a/src/cpu/pred/BranchPredictor.py b/src/cpu/pred/BranchPredictor.py index 5ae4ee8963..8589fe5d51 100644 --- a/src/cpu/pred/BranchPredictor.py +++ b/src/cpu/pred/BranchPredictor.py @@ -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" diff --git a/src/cpu/pred/SConscript b/src/cpu/pred/SConscript index c6c2a94cc8..ec3102cada 100644 --- a/src/cpu/pred/SConscript +++ b/src/cpu/pred/SConscript @@ -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') diff --git a/src/cpu/pred/bi_mode.cc b/src/cpu/pred/bi_mode.cc index 40dcbad7db..e55237f6d8 100644 --- a/src/cpu/pred/bi_mode.cc +++ b/src/cpu/pred/bi_mode.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(history); - updateGlobalHistReg(tid, true); + bp_history = static_cast(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); + 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(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(history); - updateGlobalHistReg(tid, finalPrediction); + bp_history = static_cast(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 *history = static_cast(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 diff --git a/src/cpu/pred/bi_mode.hh b/src/cpu/pred/bi_mode.hh index 721d21b79a..46c3cc2b69 100644 --- a/src/cpu/pred/bi_mode.hh +++ b/src/cpu/pred/bi_mode.hh @@ -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 { diff --git a/src/cpu/pred/bpred_unit.cc b/src/cpu/pred/bpred_unit.cc index a338cbdafd..f705b93b71 100644 --- a/src/cpu/pred/bpred_unit.cc +++ b/src/cpu/pred/bpred_unit.cc @@ -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 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 diff --git a/src/cpu/pred/bpred_unit.hh b/src/cpu/pred/bpred_unit.hh index 18f3f562cb..6aaec616c6 100644 --- a/src/cpu/pred/bpred_unit.hh +++ b/src/cpu/pred/bpred_unit.hh @@ -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 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 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 History; + typedef std::deque 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; /** * @{ diff --git a/src/cpu/pred/loop_predictor.cc b/src/cpu/pred/loop_predictor.cc index 6574d61bb1..9e34e5141a 100644 --- a/src/cpu/pred/loop_predictor.cc +++ b/src/cpu/pred/loop_predictor.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 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"), diff --git a/src/cpu/pred/loop_predictor.hh b/src/cpu/pred/loop_predictor.hh index 44d75aba35..333cb3b34e 100644 --- a/src/cpu/pred/loop_predictor.hh +++ b/src/cpu/pred/loop_predictor.hh @@ -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; diff --git a/src/cpu/pred/ltage.cc b/src/cpu/pred/ltage.cc index 930d6bf44a..3da443d20d 100644 --- a/src/cpu/pred/ltage.cc +++ b/src/cpu/pred/ltage.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 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() & 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); diff --git a/src/cpu/pred/ltage.hh b/src/cpu/pred/ltage.hh index 7deaa2bc04..92d1fd25d7 100644 --- a/src/cpu/pred/ltage.hh +++ b/src/cpu/pred/ltage.hh @@ -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; } }; diff --git a/src/cpu/pred/multiperspective_perceptron.cc b/src/cpu/pred/multiperspective_perceptron.cc index 25b4d7d39a..fd54ec8163 100644 --- a/src/cpu/pred/multiperspective_perceptron.cc +++ b/src/cpu/pred/multiperspective_perceptron.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 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 &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(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(bp_history); delete bi; + bp_history = nullptr; } } // namespace branch_prediction diff --git a/src/cpu/pred/multiperspective_perceptron.hh b/src/cpu/pred/multiperspective_perceptron.hh index 68ab5f1a23..f761607a29 100644 --- a/src/cpu/pred/multiperspective_perceptron.hh +++ b/src/cpu/pred/multiperspective_perceptron.hh @@ -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 diff --git a/src/cpu/pred/multiperspective_perceptron_tage.cc b/src/cpu/pred/multiperspective_perceptron_tage.cc index 6176d9ccb2..1075f9d04f 100644 --- a/src/cpu/pred/multiperspective_perceptron_tage.cc +++ b/src/cpu/pred/multiperspective_perceptron_tage.cc @@ -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(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(), corrTarget, + tage->condBranchUpdate(tid, pc, taken, bi->tageBranchInfo, + random_mt.random(), 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(bp_history); delete bi; + bp_history = nullptr; } } // namespace branch_prediction diff --git a/src/cpu/pred/multiperspective_perceptron_tage.hh b/src/cpu/pred/multiperspective_perceptron_tage.hh index 3a92e3cf07..9c7ee3556f 100644 --- a/src/cpu/pred/multiperspective_perceptron_tage.hh +++ b/src/cpu/pred/multiperspective_perceptron_tage.hh @@ -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; }; diff --git a/src/cpu/pred/tage.cc b/src/cpu/pred/tage.cc index 1ba52e27c7..35c0d75352 100644 --- a/src/cpu/pred/tage.cc +++ b/src/cpu/pred/tage.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 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() & 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(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(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(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(bp_history); - tage->updateHistories(tid, br_pc, true, bi->tageBranchInfo, true); + tage->updateHistories(tid, pc, taken, bi->tageBranchInfo, true); } } // namespace branch_prediction diff --git a/src/cpu/pred/tage.hh b/src/cpu/pred/tage.hh index 568f07bf9e..6d4151cb11 100644 --- a/src/cpu/pred/tage.hh +++ b/src/cpu/pred/tage.hh @@ -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 diff --git a/src/cpu/pred/tage_sc_l.cc b/src/cpu/pred/tage_sc_l.cc index 615c6230c8..a178ba6fc6 100644 --- a/src/cpu/pred/tage_sc_l.cc +++ b/src/cpu/pred/tage_sc_l.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) 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() & 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 diff --git a/src/cpu/pred/tage_sc_l.hh b/src/cpu/pred/tage_sc_l.hh index 7dead58363..6c56e69982 100644 --- a/src/cpu/pred/tage_sc_l.hh +++ b/src/cpu/pred/tage_sc_l.hh @@ -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: diff --git a/src/cpu/pred/tournament.cc b/src/cpu/pred/tournament.cc index b3a55313b7..a480497c0a 100644 --- a/src/cpu/pred/tournament.cc +++ b/src/cpu/pred/tournament.cc @@ -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(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(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(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(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(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 diff --git a/src/cpu/pred/tournament.hh b/src/cpu/pred/tournament.hh index 018d6756e4..1f404c1cce 100644 --- a/src/cpu/pred/tournament.hh +++ b/src/cpu/pred/tournament.hh @@ -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