blob: 04b95882891c35e7a9c7aea0b98adaab0a8afe84 [file] [log] [blame]
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Copyright (c) 2006 INRIA (Institut National de Recherche en
* Informatique et en Automatique / French National Research Institute
* for Computer Science and Applied Mathematics)
*
* 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.
*
* Author: André Seznec, Pau Cabre, Javier Bueno
*
*/
/*
* 8KB TAGE-SC-L branch predictor (devised by Andre Seznec)
*/
#include "cpu/pred/tage_sc_l_8KB.hh"
#include "base/random.hh"
#include "debug/TageSCL.hh"
namespace gem5
{
namespace branch_prediction
{
TAGE_SC_L_8KB_StatisticalCorrector::TAGE_SC_L_8KB_StatisticalCorrector(
const TAGE_SC_L_8KB_StatisticalCorrectorParams &p)
: StatisticalCorrector(p),
gnb(p.gnb),
logGnb(p.logGnb),
gm(p.gm)
{
initGEHLTable(gnb, gm, ggehl, logGnb, wg, 7);
}
TAGE_SC_L_8KB_StatisticalCorrector::SCThreadHistory *
TAGE_SC_L_8KB_StatisticalCorrector::makeThreadHistory()
{
SC_8KB_ThreadHistory *sh = new SC_8KB_ThreadHistory();
sh->setNumOrdinalHistories(1);
sh->initLocalHistory(1, numEntriesFirstLocalHistories, 2);
return sh;
}
unsigned
TAGE_SC_L_8KB_StatisticalCorrector::getIndBiasBank(Addr branch_pc,
BranchInfo* bi, int hitBank, int altBank) const
{
return (bi->predBeforeSC + (((hitBank+1)/4)<<4) + (bi->highConf<<1) +
(bi->lowConf <<2) +((altBank!=0)<<3)) & ((1<<logBias) -1);
}
int
TAGE_SC_L_8KB_StatisticalCorrector::gPredictions(
ThreadID tid, Addr branch_pc, BranchInfo* bi, int & lsum, int64_t phist)
{
SC_8KB_ThreadHistory *sh = static_cast<SC_8KB_ThreadHistory *>(scHistory);
lsum += gPredict(
branch_pc, sh->globalHist, gm, ggehl, gnb, logGnb, wg);
lsum += gPredict(
branch_pc, sh->bwHist, bwm, bwgehl, bwnb, logBwnb, wbw);
// only 1 local history here
lsum += gPredict(
branch_pc, sh->getLocalHistory(1, branch_pc), lm,
lgehl, lnb, logLnb, wl);
lsum += gPredict(
branch_pc, sh->imliCount, im, igehl, inb, logInb, wi);
int thres = (updateThreshold>>3)+pUpdateThreshold[getIndUpd(branch_pc)];
return thres;
}
int TAGE_SC_L_8KB_StatisticalCorrector::gIndexLogsSubstr(int nbr, int i)
{
return 0;
}
void
TAGE_SC_L_8KB_StatisticalCorrector::scHistoryUpdate(Addr branch_pc,
const StaticInstPtr &inst, bool taken, BranchInfo *tage_bi,
Addr corrTarget)
{
int brtype = inst->isDirectCtrl() ? 0 : 2;
if (! inst->isUncondCtrl()) {
++brtype;
}
// Non speculative SC histories update
if (brtype & 1) {
SC_8KB_ThreadHistory *sh =
static_cast<SC_8KB_ThreadHistory *>(scHistory);
sh->globalHist = (sh->globalHist << 1) + taken;
}
StatisticalCorrector::scHistoryUpdate(branch_pc, inst, taken, tage_bi,
corrTarget);
}
void
TAGE_SC_L_8KB_StatisticalCorrector::gUpdates(ThreadID tid, Addr pc, bool taken,
BranchInfo* bi, int64_t phist)
{
SC_8KB_ThreadHistory *sh = static_cast<SC_8KB_ThreadHistory *>(scHistory);
gUpdate(pc, taken, sh->globalHist, gm, ggehl, gnb, logGnb, wg, bi);
gUpdate(pc, taken, sh->bwHist, bwm, bwgehl, bwnb, logBwnb, wbw, bi);
gUpdate(pc, taken, sh->getLocalHistory(1, pc), lm, lgehl, lnb, logLnb, wl,
bi);
gUpdate(pc, taken, sh->imliCount, im, igehl, inb, logInb, wi, bi);
}
TAGE_SC_L_8KB::TAGE_SC_L_8KB(const TAGE_SC_L_8KBParams &params)
: TAGE_SC_L(params)
{
}
void
TAGE_SC_L_TAGE_8KB::initFoldedHistories(ThreadHistory & history)
{
// Some hardcoded values are used here
// (they do not seem to depend on any parameter)
for (int i = 1; i <= nHistoryTables; i++) {
history.computeIndices[i].init(
histLengths[i], 17 + (2 * ((i - 1) / 2) % 4));
history.computeTags[0][i].init(
history.computeIndices[i].origLength, 13);
history.computeTags[1][i].init(
history.computeIndices[i].origLength, 11);
DPRINTF(TageSCL, "HistLength:%d, TTSize:%d, TTTWidth:%d\n",
histLengths[i], logTagTableSizes[i], tagTableTagWidths[i]);
}
}
int
TAGE_SC_L_TAGE_8KB::gindex_ext(int index, int bank) const
{
return (index ^ (index >> logTagTableSizes[bank])
^ (index >> 2 * logTagTableSizes[bank]));
}
uint16_t
TAGE_SC_L_TAGE_8KB::gtag(ThreadID tid, Addr pc, int bank) const
{
int tag = (threadHistory[tid].computeIndices[bank - 1].comp << 2) ^ pc ^
(pc >> instShiftAmt) ^
threadHistory[tid].computeIndices[bank].comp;
int hlen = (histLengths[bank] > pathHistBits) ? pathHistBits :
histLengths[bank];
tag = (tag >> 1) ^ ((tag & 1) << 10) ^
F(threadHistory[tid].pathHist, hlen, bank);
tag ^= threadHistory[tid].computeTags[0][bank].comp ^
(threadHistory[tid].computeTags[1][bank].comp << 1);
return ((tag ^ (tag >> tagTableTagWidths[bank]))
& ((1ULL << tagTableTagWidths[bank]) - 1));
}
void
TAGE_SC_L_TAGE_8KB::handleAllocAndUReset(
bool alloc, bool taken, TAGEBase::BranchInfo* bi, int nrand)
{
if (!alloc) {
return;
}
int penalty = 0;
int truePen = 0;
int numAllocated = 0;
bool maxAllocReached = false;
for (int I = calcDep(bi); I < nHistoryTables; I += 2) {
// Handle the 2-way associativity for allocation
for (int j = 0; j < 2; ++j) {
int i = ((j == 0) ? I : (I ^ 1)) + 1;
if (i > nHistoryTables) {
break;
}
if (noSkip[i]) {
if (gtable[i][bi->tableIndices[i]].u == 0) {
gtable[i][bi->tableIndices[i]].u =
((random_mt.random<int>() & 31) == 0);
// protect randomly from fast replacement
gtable[i][bi->tableIndices[i]].tag = bi->tableTags[i];
gtable[i][bi->tableIndices[i]].ctr = taken ? 0 : -1;
numAllocated++;
if (numAllocated == maxNumAlloc) {
maxAllocReached = true;
break;
}
I += 2;
} else {
int8_t ctr = gtable[i][bi->tableIndices[i]].ctr;
if ((gtable[i][bi->tableIndices[i]].u == 1) &
(abs (2 * ctr + 1) == 1)) {
if ((random_mt.random<int>() & 7) == 0) {
gtable[i][bi->tableIndices[i]].u = 0;
}
} else {
truePen++;
}
penalty++;
}
} else {
break;
}
}
if (maxAllocReached) {
break;
}
}
tCounter += (truePen + penalty - 5 * numAllocated);
handleUReset();
}
void
TAGE_SC_L_TAGE_8KB::resetUctr(uint8_t & u)
{
// On real HW it should be u >>= 1 instead of if > 0 then u--
if (u > 0) {
u--;
}
}
void
TAGE_SC_L_TAGE_8KB::handleTAGEUpdate(Addr branch_pc, bool taken,
TAGEBase::BranchInfo* bi)
{
if (bi->hitBank > 0) {
if (abs (2 * gtable[bi->hitBank][bi->hitBankIndex].ctr + 1) == 1) {
if (bi->longestMatchPred != taken) { // acts as a protection
if (bi->altBank > 0) {
int8_t ctr = gtable[bi->altBank][bi->altBankIndex].ctr;
if (abs (2 * ctr + 1) == 1) {
gtable[bi->altBank][bi->altBankIndex].u = 0;
}
//just mute from protected to unprotected
ctrUpdate(gtable[bi->altBank][bi->altBankIndex].ctr, taken,
tagTableCounterBits);
ctr = gtable[bi->altBank][bi->altBankIndex].ctr;
if (abs (2 * ctr + 1) == 1) {
gtable[bi->altBank][bi->altBankIndex].u = 0;
}
}
if (bi->altBank == 0) {
baseUpdate(branch_pc, taken, bi);
}
}
}
//just mute from protected to unprotected
if (abs (2 * gtable[bi->hitBank][bi->hitBankIndex].ctr + 1) == 1) {
gtable[bi->hitBank][bi->hitBankIndex].u = 0;
}
ctrUpdate(gtable[bi->hitBank][bi->hitBankIndex].ctr, taken,
tagTableCounterBits);
//sign changes: no way it can have been useful
if (abs (2 * gtable[bi->hitBank][bi->hitBankIndex].ctr + 1) == 1) {
gtable[bi->hitBank][bi->hitBankIndex].u = 0;
}
if (bi->altTaken == taken) {
if (bi->altBank > 0) {
int8_t ctr = gtable[bi->altBank][bi->altBankIndex].ctr;
if (abs (2*ctr + 1) == 7) {
if (gtable[bi->hitBank][bi->hitBankIndex].u == 1) {
if (bi->longestMatchPred == taken) {
gtable[bi->hitBank][bi->hitBankIndex].u = 0;
}
}
}
}
}
} else {
baseUpdate(branch_pc, taken, bi);
}
if ((bi->longestMatchPred != bi->altTaken) &&
(bi->longestMatchPred == taken) &&
(gtable[bi->hitBank][bi->hitBankIndex].u < (1 << tagTableUBits) -1)) {
gtable[bi->hitBank][bi->hitBankIndex].u++;
}
}
} // namespace branch_prediction
} // namespace gem5