cpu: Add an indirect branch target predictor
This patch adds a configurable indirect branch predictor that can be indexed by a combination of GHR and path history hashes. Implements the functionality described in: "Target prediction for indirect jumps" by Chang, Hao, and Patt http://dl.acm.org/citation.cfm?id=264209
This commit is contained in:
parent
7bc52af771
commit
1578d2d0b6
10 changed files with 426 additions and 27 deletions
|
@ -42,6 +42,16 @@ class BranchPredictor(SimObject):
|
||||||
RASSize = Param.Unsigned(16, "RAS size")
|
RASSize = Param.Unsigned(16, "RAS size")
|
||||||
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
|
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
|
||||||
|
|
||||||
|
useIndirect = Param.Bool(True, "Use indirect branch predictor")
|
||||||
|
indirectHashGHR = Param.Bool(True, "Hash branch predictor GHR")
|
||||||
|
indirectHashTargets = Param.Bool(True, "Hash path history targets")
|
||||||
|
indirectSets = Param.Unsigned(256, "Cache sets for indirect predictor")
|
||||||
|
indirectWays = Param.Unsigned(2, "Ways for indirect predictor")
|
||||||
|
indirectTagSize = Param.Unsigned(16, "Indirect target cache tag bits")
|
||||||
|
indirectPathLength = Param.Unsigned(3,
|
||||||
|
"Previous indirect targets to use for path history")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LocalBP(BranchPredictor):
|
class LocalBP(BranchPredictor):
|
||||||
type = 'LocalBP'
|
type = 'LocalBP'
|
||||||
|
|
|
@ -35,9 +35,11 @@ if env['TARGET_ISA'] == 'null':
|
||||||
|
|
||||||
SimObject('BranchPredictor.py')
|
SimObject('BranchPredictor.py')
|
||||||
|
|
||||||
|
DebugFlag('Indirect')
|
||||||
Source('bpred_unit.cc')
|
Source('bpred_unit.cc')
|
||||||
Source('2bit_local.cc')
|
Source('2bit_local.cc')
|
||||||
Source('btb.cc')
|
Source('btb.cc')
|
||||||
|
Source('indirect.cc')
|
||||||
Source('ras.cc')
|
Source('ras.cc')
|
||||||
Source('tournament.cc')
|
Source('tournament.cc')
|
||||||
Source ('bi_mode.cc')
|
Source ('bi_mode.cc')
|
||||||
|
|
|
@ -236,6 +236,12 @@ BiModeBP::retireSquashed(void *bp_history)
|
||||||
delete history;
|
delete history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
BiModeBP::getGHR(void *bp_history) const
|
||||||
|
{
|
||||||
|
return static_cast<BPHistory*>(bp_history)->globalHistoryReg;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BiModeBP::updateGlobalHistReg(bool taken)
|
BiModeBP::updateGlobalHistReg(bool taken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,7 @@ class BiModeBP : public BPredUnit
|
||||||
void btbUpdate(Addr branch_addr, void * &bp_history);
|
void btbUpdate(Addr branch_addr, void * &bp_history);
|
||||||
void update(Addr branch_addr, bool taken, void *bp_history, bool squashed);
|
void update(Addr branch_addr, bool taken, void *bp_history, bool squashed);
|
||||||
void retireSquashed(void *bp_history);
|
void retireSquashed(void *bp_history);
|
||||||
|
unsigned getGHR(void *bp_history) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateGlobalHistReg(bool taken);
|
void updateGlobalHistReg(bool taken);
|
||||||
|
|
|
@ -62,6 +62,15 @@ BPredUnit::BPredUnit(const Params *params)
|
||||||
params->instShiftAmt,
|
params->instShiftAmt,
|
||||||
params->numThreads),
|
params->numThreads),
|
||||||
RAS(numThreads),
|
RAS(numThreads),
|
||||||
|
useIndirect(params->useIndirect),
|
||||||
|
iPred(params->indirectHashGHR,
|
||||||
|
params->indirectHashTargets,
|
||||||
|
params->indirectSets,
|
||||||
|
params->indirectWays,
|
||||||
|
params->indirectTagSize,
|
||||||
|
params->indirectPathLength,
|
||||||
|
params->instShiftAmt,
|
||||||
|
params->numThreads),
|
||||||
instShiftAmt(params->instShiftAmt)
|
instShiftAmt(params->instShiftAmt)
|
||||||
{
|
{
|
||||||
for (auto& r : RAS)
|
for (auto& r : RAS)
|
||||||
|
@ -117,6 +126,27 @@ BPredUnit::regStats()
|
||||||
.name(name() + ".RASInCorrect")
|
.name(name() + ".RASInCorrect")
|
||||||
.desc("Number of incorrect RAS predictions.")
|
.desc("Number of incorrect RAS predictions.")
|
||||||
;
|
;
|
||||||
|
|
||||||
|
indirectLookups
|
||||||
|
.name(name() + ".indirectLookups")
|
||||||
|
.desc("Number of indirect predictor lookups.")
|
||||||
|
;
|
||||||
|
|
||||||
|
indirectHits
|
||||||
|
.name(name() + ".indirectHits")
|
||||||
|
.desc("Number of indirect target hits.")
|
||||||
|
;
|
||||||
|
|
||||||
|
indirectMisses
|
||||||
|
.name(name() + ".indirectMisses")
|
||||||
|
.desc("Number of indirect misses.")
|
||||||
|
;
|
||||||
|
|
||||||
|
indirectMispredicted
|
||||||
|
.name(name() + "indirectMispredcited")
|
||||||
|
.desc("Number of mispredicted indirect branches.")
|
||||||
|
;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProbePoints::PMUUPtr
|
ProbePoints::PMUUPtr
|
||||||
|
@ -216,10 +246,12 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
tid, pc, pc, RAS[tid].topIdx());
|
tid, pc, pc, RAS[tid].topIdx());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inst->isDirectCtrl() || !useIndirect) {
|
||||||
|
// Check BTB on direct branches
|
||||||
if (BTB.valid(pc.instAddr(), tid)) {
|
if (BTB.valid(pc.instAddr(), tid)) {
|
||||||
++BTBHits;
|
++BTBHits;
|
||||||
|
|
||||||
// If it's not a return, use the BTB to get the target addr.
|
// If it's not a return, use the BTB to get target addr.
|
||||||
target = BTB.lookup(pc.instAddr(), tid);
|
target = BTB.lookup(pc.instAddr(), tid);
|
||||||
|
|
||||||
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
|
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
|
||||||
|
@ -229,8 +261,8 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
|
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
|
||||||
"valid entry.\n",tid);
|
"valid entry.\n",tid);
|
||||||
pred_taken = false;
|
pred_taken = false;
|
||||||
// The Direction of the branch predictor is altered because the
|
// The Direction of the branch predictor is altered
|
||||||
// BTB did not have an entry
|
// because the BTB did not have an entry
|
||||||
// The predictor needs to be updated accordingly
|
// The predictor needs to be updated accordingly
|
||||||
if (!inst->isCall() && !inst->isReturn()) {
|
if (!inst->isCall() && !inst->isReturn()) {
|
||||||
btbUpdate(pc.instAddr(), bp_history);
|
btbUpdate(pc.instAddr(), bp_history);
|
||||||
|
@ -242,6 +274,32 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
}
|
}
|
||||||
TheISA::advancePC(target, inst);
|
TheISA::advancePC(target, inst);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
predict_record.wasIndirect = true;
|
||||||
|
++indirectLookups;
|
||||||
|
//Consult indirect predictor on indirect control
|
||||||
|
if (iPred.lookup(pc.instAddr(), getGHR(bp_history), target,
|
||||||
|
tid)) {
|
||||||
|
// Indirect predictor hit
|
||||||
|
++indirectHits;
|
||||||
|
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted "
|
||||||
|
"indirect target is %s.\n", tid, pc, target);
|
||||||
|
} else {
|
||||||
|
++indirectMisses;
|
||||||
|
pred_taken = false;
|
||||||
|
DPRINTF(Branch, "[tid:%i]: Instruction %s no indirect "
|
||||||
|
"target.\n", tid, pc);
|
||||||
|
if (!inst->isCall() && !inst->isReturn()) {
|
||||||
|
|
||||||
|
} else if (inst->isCall() && !inst->isUncondCtrl()) {
|
||||||
|
RAS[tid].pop();
|
||||||
|
predict_record.pushedRAS = false;
|
||||||
|
}
|
||||||
|
TheISA::advancePC(target, inst);
|
||||||
|
}
|
||||||
|
iPred.recordIndirect(pc.instAddr(), target.instAddr(), seqNum,
|
||||||
|
tid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (inst->isReturn()) {
|
if (inst->isReturn()) {
|
||||||
|
@ -388,6 +446,7 @@ BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
|
||||||
DPRINTF(Branch, "[tid:%i]: Committing branches until "
|
DPRINTF(Branch, "[tid:%i]: Committing branches until "
|
||||||
"[sn:%lli].\n", tid, done_sn);
|
"[sn:%lli].\n", tid, done_sn);
|
||||||
|
|
||||||
|
iPred.commit(done_sn, tid);
|
||||||
while (!predHist[tid].empty() &&
|
while (!predHist[tid].empty() &&
|
||||||
predHist[tid].back().seqNum <= done_sn) {
|
predHist[tid].back().seqNum <= done_sn) {
|
||||||
// Update the branch predictor with the correct results.
|
// Update the branch predictor with the correct results.
|
||||||
|
@ -407,6 +466,7 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
|
||||||
{
|
{
|
||||||
History &pred_hist = predHist[tid];
|
History &pred_hist = predHist[tid];
|
||||||
|
|
||||||
|
iPred.squash(squashed_sn, tid);
|
||||||
while (!pred_hist.empty() &&
|
while (!pred_hist.empty() &&
|
||||||
pred_hist.front().seqNum > squashed_sn) {
|
pred_hist.front().seqNum > squashed_sn) {
|
||||||
if (pred_hist.front().usedRAS) {
|
if (pred_hist.front().usedRAS) {
|
||||||
|
@ -485,8 +545,13 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
|
||||||
|
|
||||||
if ((*hist_it).usedRAS) {
|
if ((*hist_it).usedRAS) {
|
||||||
++RASIncorrect;
|
++RASIncorrect;
|
||||||
|
DPRINTF(Branch, "[tid:%i]: Incorrect RAS [sn:%i]\n",
|
||||||
|
tid, hist_it->seqNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Have to get GHR here because the update deletes bpHistory
|
||||||
|
unsigned ghr = getGHR(hist_it->bpHistory);
|
||||||
|
|
||||||
update((*hist_it).pc, actually_taken,
|
update((*hist_it).pc, actually_taken,
|
||||||
pred_hist.front().bpHistory, true);
|
pred_hist.front().bpHistory, true);
|
||||||
hist_it->wasSquashed = true;
|
hist_it->wasSquashed = true;
|
||||||
|
@ -499,12 +564,15 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
|
||||||
RAS[tid].pop();
|
RAS[tid].pop();
|
||||||
hist_it->usedRAS = true;
|
hist_it->usedRAS = true;
|
||||||
}
|
}
|
||||||
|
if (hist_it->wasIndirect) {
|
||||||
|
++indirectMispredicted;
|
||||||
|
iPred.recordTarget(hist_it->seqNum, ghr, corrTarget, tid);
|
||||||
|
} else {
|
||||||
DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
|
DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
|
||||||
" PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
|
" PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
|
||||||
|
|
||||||
BTB.update((*hist_it).pc, corrTarget, tid);
|
BTB.update((*hist_it).pc, corrTarget, tid);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//Actually not Taken
|
//Actually not Taken
|
||||||
if (hist_it->usedRAS) {
|
if (hist_it->usedRAS) {
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
#include "base/types.hh"
|
#include "base/types.hh"
|
||||||
#include "cpu/pred/btb.hh"
|
#include "cpu/pred/btb.hh"
|
||||||
|
#include "cpu/pred/indirect.hh"
|
||||||
#include "cpu/pred/ras.hh"
|
#include "cpu/pred/ras.hh"
|
||||||
#include "cpu/inst_seq.hh"
|
#include "cpu/inst_seq.hh"
|
||||||
#include "cpu/static_inst.hh"
|
#include "cpu/static_inst.hh"
|
||||||
|
@ -197,6 +198,9 @@ class BPredUnit : public SimObject
|
||||||
void BTBUpdate(Addr instPC, const TheISA::PCState &target)
|
void BTBUpdate(Addr instPC, const TheISA::PCState &target)
|
||||||
{ BTB.update(instPC, target, 0); }
|
{ BTB.update(instPC, target, 0); }
|
||||||
|
|
||||||
|
|
||||||
|
virtual unsigned getGHR(void* bp_history) const { return 0; }
|
||||||
|
|
||||||
void dump();
|
void dump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -210,7 +214,7 @@ class BPredUnit : public SimObject
|
||||||
ThreadID _tid)
|
ThreadID _tid)
|
||||||
: seqNum(seq_num), pc(instPC), bpHistory(bp_history), RASTarget(0),
|
: seqNum(seq_num), pc(instPC), bpHistory(bp_history), RASTarget(0),
|
||||||
RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), pushedRAS(0),
|
RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), pushedRAS(0),
|
||||||
wasCall(0), wasReturn(0), wasSquashed(0)
|
wasCall(0), wasReturn(0), wasSquashed(0), wasIndirect(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator==(const PredictorHistory &entry) const {
|
bool operator==(const PredictorHistory &entry) const {
|
||||||
|
@ -255,6 +259,9 @@ class BPredUnit : public SimObject
|
||||||
|
|
||||||
/** Whether this instruction has already mispredicted/updated bp */
|
/** Whether this instruction has already mispredicted/updated bp */
|
||||||
bool wasSquashed;
|
bool wasSquashed;
|
||||||
|
|
||||||
|
/** Wether this instruction was an indirect branch */
|
||||||
|
bool wasIndirect;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::deque<PredictorHistory> History;
|
typedef std::deque<PredictorHistory> History;
|
||||||
|
@ -276,6 +283,12 @@ class BPredUnit : public SimObject
|
||||||
/** The per-thread return address stack. */
|
/** The per-thread return address stack. */
|
||||||
std::vector<ReturnAddrStack> RAS;
|
std::vector<ReturnAddrStack> RAS;
|
||||||
|
|
||||||
|
/** Option to disable indirect predictor. */
|
||||||
|
const bool useIndirect;
|
||||||
|
|
||||||
|
/** The indirect target predictor. */
|
||||||
|
IndirectPredictor iPred;
|
||||||
|
|
||||||
/** Stat for number of BP lookups. */
|
/** Stat for number of BP lookups. */
|
||||||
Stats::Scalar lookups;
|
Stats::Scalar lookups;
|
||||||
/** Stat for number of conditional branches predicted. */
|
/** Stat for number of conditional branches predicted. */
|
||||||
|
@ -295,6 +308,15 @@ class BPredUnit : public SimObject
|
||||||
/** Stat for number of times the RAS is incorrect. */
|
/** Stat for number of times the RAS is incorrect. */
|
||||||
Stats::Scalar RASIncorrect;
|
Stats::Scalar RASIncorrect;
|
||||||
|
|
||||||
|
/** Stat for the number of indirect target lookups.*/
|
||||||
|
Stats::Scalar indirectLookups;
|
||||||
|
/** Stat for the number of indirect target hits.*/
|
||||||
|
Stats::Scalar indirectHits;
|
||||||
|
/** Stat for the number of indirect target misses.*/
|
||||||
|
Stats::Scalar indirectMisses;
|
||||||
|
/** Stat for the number of indirect target mispredictions.*/
|
||||||
|
Stats::Scalar indirectMispredicted;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Number of bits to shift instructions by for predictor addresses. */
|
/** Number of bits to shift instructions by for predictor addresses. */
|
||||||
const unsigned instShiftAmt;
|
const unsigned instShiftAmt;
|
||||||
|
|
185
src/cpu/pred/indirect.cc
Normal file
185
src/cpu/pred/indirect.cc
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 ARM Limited
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Mitch Hayenga
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cpu/pred/indirect.hh"
|
||||||
|
|
||||||
|
#include "base/intmath.hh"
|
||||||
|
#include "debug/Indirect.hh"
|
||||||
|
|
||||||
|
IndirectPredictor::IndirectPredictor(bool hash_ghr, bool hash_targets,
|
||||||
|
unsigned num_sets, unsigned num_ways,
|
||||||
|
unsigned tag_bits, unsigned path_len, unsigned inst_shift,
|
||||||
|
unsigned num_threads)
|
||||||
|
: hashGHR(hash_ghr), hashTargets(hash_targets),
|
||||||
|
numSets(num_sets), numWays(num_ways), tagBits(tag_bits),
|
||||||
|
pathLength(path_len), instShift(inst_shift)
|
||||||
|
{
|
||||||
|
if (!isPowerOf2(numSets)) {
|
||||||
|
panic("Indirect predictor requires power of 2 number of sets");
|
||||||
|
}
|
||||||
|
|
||||||
|
threadInfo.resize(num_threads);
|
||||||
|
|
||||||
|
targetCache.resize(numSets);
|
||||||
|
for (unsigned i = 0; i < numSets; i++) {
|
||||||
|
targetCache[i].resize(numWays);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IndirectPredictor::lookup(Addr br_addr, unsigned ghr, TheISA::PCState& target,
|
||||||
|
ThreadID tid)
|
||||||
|
{
|
||||||
|
Addr set_index = getSetIndex(br_addr, ghr, tid);
|
||||||
|
Addr tag = getTag(br_addr);
|
||||||
|
|
||||||
|
assert(set_index < numSets);
|
||||||
|
|
||||||
|
DPRINTF(Indirect, "Looking up %x (set:%d)\n", br_addr, set_index);
|
||||||
|
const auto &iset = targetCache[set_index];
|
||||||
|
for (auto way = iset.begin(); way != iset.end(); ++way) {
|
||||||
|
if (way->tag == tag) {
|
||||||
|
DPRINTF(Indirect, "Hit %x (target:%s)\n", br_addr, way->target);
|
||||||
|
target = way->target;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DPRINTF(Indirect, "Miss %x\n", br_addr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IndirectPredictor::recordIndirect(Addr br_addr, Addr tgt_addr,
|
||||||
|
InstSeqNum seq_num, ThreadID tid)
|
||||||
|
{
|
||||||
|
DPRINTF(Indirect, "Recording %x seq:%d\n", br_addr, seq_num);
|
||||||
|
HistoryEntry entry(br_addr, tgt_addr, seq_num);
|
||||||
|
threadInfo[tid].pathHist.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IndirectPredictor::commit(InstSeqNum seq_num, ThreadID tid)
|
||||||
|
{
|
||||||
|
DPRINTF(Indirect, "Committing seq:%d\n", seq_num);
|
||||||
|
ThreadInfo &t_info = threadInfo[tid];
|
||||||
|
|
||||||
|
if (t_info.pathHist.empty()) return;
|
||||||
|
|
||||||
|
if (t_info.headHistEntry < t_info.pathHist.size() &&
|
||||||
|
t_info.pathHist[t_info.headHistEntry].seqNum <= seq_num) {
|
||||||
|
if (t_info.headHistEntry >= pathLength) {
|
||||||
|
t_info.pathHist.pop_front();
|
||||||
|
} else {
|
||||||
|
++t_info.headHistEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IndirectPredictor::squash(InstSeqNum seq_num, ThreadID tid)
|
||||||
|
{
|
||||||
|
DPRINTF(Indirect, "Squashing seq:%d\n", seq_num);
|
||||||
|
ThreadInfo &t_info = threadInfo[tid];
|
||||||
|
auto squash_itr = t_info.pathHist.begin();
|
||||||
|
while (squash_itr != t_info.pathHist.end()) {
|
||||||
|
if (squash_itr->seqNum > seq_num) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++squash_itr;
|
||||||
|
}
|
||||||
|
if (squash_itr != t_info.pathHist.end()) {
|
||||||
|
DPRINTF(Indirect, "Squashing series starting with sn:%d\n",
|
||||||
|
squash_itr->seqNum);
|
||||||
|
}
|
||||||
|
t_info.pathHist.erase(squash_itr, t_info.pathHist.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndirectPredictor::recordTarget(InstSeqNum seq_num, unsigned ghr,
|
||||||
|
const TheISA::PCState& target, ThreadID tid)
|
||||||
|
{
|
||||||
|
ThreadInfo &t_info = threadInfo[tid];
|
||||||
|
|
||||||
|
// Should have just squashed so this branch should be the oldest
|
||||||
|
auto hist_entry = *(t_info.pathHist.rbegin());
|
||||||
|
// Temporarily pop it off the history so we can calculate the set
|
||||||
|
t_info.pathHist.pop_back();
|
||||||
|
Addr set_index = getSetIndex(hist_entry.pcAddr, ghr, tid);
|
||||||
|
Addr tag = getTag(hist_entry.pcAddr);
|
||||||
|
hist_entry.targetAddr = target.instAddr();
|
||||||
|
t_info.pathHist.push_back(hist_entry);
|
||||||
|
|
||||||
|
assert(set_index < numSets);
|
||||||
|
|
||||||
|
auto &iset = targetCache[set_index];
|
||||||
|
for (auto way = iset.begin(); way != iset.end(); ++way) {
|
||||||
|
if (way->tag == tag) {
|
||||||
|
DPRINTF(Indirect, "Updating Target (seq: %d br:%x set:%d target:"
|
||||||
|
"%s)\n", seq_num, hist_entry.pcAddr, set_index, target);
|
||||||
|
way->target = target;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(Indirect, "Allocating Target (seq: %d br:%x set:%d target:%s)\n",
|
||||||
|
seq_num, hist_entry.pcAddr, set_index, target);
|
||||||
|
// Did not find entry, random replacement
|
||||||
|
auto &way = iset[rand() % numWays];
|
||||||
|
way.tag = tag;
|
||||||
|
way.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Addr
|
||||||
|
IndirectPredictor::getSetIndex(Addr br_addr, unsigned ghr, ThreadID tid)
|
||||||
|
{
|
||||||
|
ThreadInfo &t_info = threadInfo[tid];
|
||||||
|
|
||||||
|
Addr hash = br_addr >> instShift;
|
||||||
|
if (hashGHR) {
|
||||||
|
hash ^= ghr;
|
||||||
|
}
|
||||||
|
if (hashTargets) {
|
||||||
|
unsigned hash_shift = floorLog2(numSets) / pathLength;
|
||||||
|
for (int i = t_info.pathHist.size()-1, p = 0;
|
||||||
|
i >= 0 && p < pathLength; i--, p++) {
|
||||||
|
hash ^= (t_info.pathHist[i].targetAddr >>
|
||||||
|
(instShift + p*hash_shift));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash & (numSets-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Addr
|
||||||
|
IndirectPredictor::getTag(Addr br_addr)
|
||||||
|
{
|
||||||
|
return (br_addr >> instShift) & ((0x1<<tagBits)-1);
|
||||||
|
}
|
97
src/cpu/pred/indirect.hh
Normal file
97
src/cpu/pred/indirect.hh
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 ARM Limited
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Mitch Hayenga
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CPU_PRED_INDIRECT_HH__
|
||||||
|
#define __CPU_PRED_INDIRECT_HH__
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include "arch/isa_traits.hh"
|
||||||
|
#include "config/the_isa.hh"
|
||||||
|
#include "cpu/inst_seq.hh"
|
||||||
|
|
||||||
|
class IndirectPredictor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IndirectPredictor(bool hash_ghr, bool hash_targets,
|
||||||
|
unsigned num_sets, unsigned num_ways,
|
||||||
|
unsigned tag_bits, unsigned path_len,
|
||||||
|
unsigned inst_shift, unsigned num_threads);
|
||||||
|
bool lookup(Addr br_addr, unsigned ghr, TheISA::PCState& br_target,
|
||||||
|
ThreadID tid);
|
||||||
|
void recordIndirect(Addr br_addr, Addr tgt_addr, InstSeqNum seq_num,
|
||||||
|
ThreadID tid);
|
||||||
|
void commit(InstSeqNum seq_num, ThreadID tid);
|
||||||
|
void squash(InstSeqNum seq_num, ThreadID tid);
|
||||||
|
void recordTarget(InstSeqNum seq_num, unsigned ghr,
|
||||||
|
const TheISA::PCState& target, ThreadID tid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const bool hashGHR;
|
||||||
|
const bool hashTargets;
|
||||||
|
const unsigned numSets;
|
||||||
|
const unsigned numWays;
|
||||||
|
const unsigned tagBits;
|
||||||
|
const unsigned pathLength;
|
||||||
|
const unsigned instShift;
|
||||||
|
|
||||||
|
struct IPredEntry
|
||||||
|
{
|
||||||
|
IPredEntry() : tag(0), target(0) { }
|
||||||
|
Addr tag;
|
||||||
|
TheISA::PCState target;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::vector<IPredEntry> > targetCache;
|
||||||
|
|
||||||
|
Addr getSetIndex(Addr br_addr, unsigned ghr, ThreadID tid);
|
||||||
|
Addr getTag(Addr br_addr);
|
||||||
|
|
||||||
|
struct HistoryEntry
|
||||||
|
{
|
||||||
|
HistoryEntry(Addr br_addr, Addr tgt_addr, InstSeqNum seq_num)
|
||||||
|
: pcAddr(br_addr), targetAddr(tgt_addr), seqNum(seq_num) { }
|
||||||
|
Addr pcAddr;
|
||||||
|
Addr targetAddr;
|
||||||
|
InstSeqNum seqNum;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ThreadInfo {
|
||||||
|
ThreadInfo() : headHistEntry(0) { }
|
||||||
|
|
||||||
|
std::deque<HistoryEntry> pathHist;
|
||||||
|
unsigned headHistEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ThreadInfo> threadInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __CPU_PRED_INDIRECT_HH__
|
|
@ -388,6 +388,12 @@ TournamentBPParams::create()
|
||||||
return new TournamentBP(this);
|
return new TournamentBP(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
TournamentBP::getGHR(void *bp_history) const
|
||||||
|
{
|
||||||
|
return static_cast<BPHistory *>(bp_history)->globalHistory;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
int
|
int
|
||||||
TournamentBP::BPHistory::newCount = 0;
|
TournamentBP::BPHistory::newCount = 0;
|
||||||
|
|
|
@ -114,6 +114,8 @@ class TournamentBP : public BPredUnit
|
||||||
*/
|
*/
|
||||||
void squash(void *bp_history);
|
void squash(void *bp_history);
|
||||||
|
|
||||||
|
unsigned getGHR(void *bp_history) const;
|
||||||
|
|
||||||
/** Returns the global history. */
|
/** Returns the global history. */
|
||||||
inline unsigned readGlobalHist() { return globalHistory; }
|
inline unsigned readGlobalHist() { return globalHistory; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue