blob: 68ab5f1a232e8b80436260a6cac8b84d6546380c [file] [log] [blame]
/*
* Copyright 2019 Texas A&M University
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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
* HOLDER 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: Daniel A. Jiménez
* Adapted to gem5 by: Javier Bueno Hedo
*
*/
/*
* Multiperspective Perceptron Predictor (by Daniel A. Jiménez)
*/
#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__
#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__
#include <array>
#include <vector>
#include "cpu/pred/bpred_unit.hh"
#include "params/MultiperspectivePerceptron.hh"
namespace gem5
{
namespace branch_prediction
{
class MultiperspectivePerceptron : public BPredUnit
{
protected:
/**
* Branch information data
*/
class MPPBranchInfo
{
/** pc of the branch */
const unsigned int pc;
/** pc of the branch, shifted 2 bits to the right */
const unsigned short int pc2;
/** pc of the branch, hashed */
const unsigned short int hpc;
/** Whether this is a conditional branch */
const bool condBranch;
/**
* PC Hash functions
*/
static inline unsigned int hash1(unsigned int a)
{
a = (a ^ 0xdeadbeef) + (a<<4);
a = a ^ (a>>10);
a = a + (a<<7);
a = a ^ (a>>13);
return a;
}
static inline unsigned int hash2(unsigned int key)
{
int c2 = 0x27d4eb2d; // a prime or an odd constant
key = (key ^ 61) ^ (key >> 16);
key = key + (key << 3);
key = key ^ (key >> 4);
key = key * c2;
key = key ^ (key >> 15);
return key;
}
static inline unsigned int hash(unsigned int key, unsigned int i)
{
return hash2(key) * i + hash1(key);
}
static inline unsigned int hashPC(unsigned int pc, int pcshift)
{
if (pcshift < 0) {
return hash(pc, -pcshift);
} else if (pcshift < 11) {
unsigned int x = pc;
x ^= (pc >> pcshift);
return x;
} else {
return pc >> (pcshift-11);
}
}
public:
/** Whether this branch has been filtered by the prefetcher */
bool filtered;
/** Result of the prediction (true is taken) */
bool prediction;
/** Score of the perceptron */
int yout;
MPPBranchInfo(Addr _pc, int pcshift, bool cb) : pc((unsigned int)_pc),
pc2(pc >> 2), hpc(hashPC(pc, pcshift)), condBranch(cb),
filtered(false), prediction(false), yout(0)
{ }
unsigned int getPC() const
{
return pc;
}
unsigned short int getPC2() const
{
return pc2;
}
unsigned short int getHPC() const
{
return hpc;
}
unsigned int getHashFilter(bool last_ghist_bit) const
{
return last_ghist_bit ^ hpc;
}
bool isUnconditional() const
{
return !condBranch;
}
};
/**
* Entry of the branch filter
*/
struct FilterEntry
{
/** Has this branch been taken at least once? */
bool seenTaken;
/** Has this branch been not taken at least once? */
bool seenUntaken;
FilterEntry() : seenTaken(false), seenUntaken(false) {}
/** Whether this branch has always been observed as not taken */
bool alwaysNotTakenSoFar() const {
return seenUntaken & !seenTaken;
}
/** Whether this branch has always been observed as taken */
bool alwaysTakenSoFar() const {
return seenTaken & !seenUntaken;
}
/** Whether this branch has been observed before */
bool neverSeen() const {
return !seenTaken && !seenUntaken;
}
};
/**
* Local history entries, each enty contains the history of directions
* taken by a given branch.
*/
class LocalHistories
{
/** The array of histories */
std::vector<unsigned int> localHistories;
/** Size in bits of each history entry */
const int localHistoryLength;
/** Index function given the pc of the branch */
unsigned int index(Addr pc) const {
return (pc >> 2) % localHistories.size();
}
public:
LocalHistories(int nlocal_histories, int histo_len) :
localHistories(nlocal_histories), localHistoryLength(histo_len) {}
/** Obtains the local history entry of a given branch */
unsigned int operator[](Addr pc) const
{
return localHistories[index(pc)];
}
/** Adds a history bit to the local history entry of a given branch */
void update(Addr pc, bool value)
{
assert(localHistories.size() > 0);
unsigned int &pos = localHistories[index(pc)];
pos <<= 1;
pos |= value;
pos &= ((1<<localHistoryLength)-1);
}
/** Returns the number of bits of each local history entry */
int getLocalHistoryLength() const
{
return localHistoryLength;
}
/** Size in bits required by all history entries */
int getSize() const
{
return localHistoryLength * localHistories.size();
}
};
/**
* Base class to implement the predictor tables.
*/
struct HistorySpec
{
/** First parameter */
const int p1;
/** Second parameter */
const int p2;
/** Third parameter */
const int p3;
/** Coefficient of the feature, models the accuracy of the feature */
const double coeff;
/** Pre-assigned size in bits assigned to this feature */
const int size;
/** Width of the table in bits */
const int width;
/** Reference to the branch predictor class */
MultiperspectivePerceptron &mpp;
HistorySpec(int _p1, int _p2, int _p3, double _coeff, int _size,
int _width, MultiperspectivePerceptron &_mpp) : p1(_p1),
p2(_p2), p3(_p3), coeff(_coeff), size(_size), width(_width),
mpp(_mpp)
{}
/**
* Gets the hash to index the table, using the pc of the branch,
* and the index of the table.
* @param tid Thread ID of the branch
* @param pc address of the branch
* @param pc2 address of the branch shifted 2 bits to the right
* @param t integer index of the table
* @result resulting hash value that will be used to index the table
*/
virtual unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t)
const = 0;
/**
* Sets the size requirements of the table, used when initializing
* to set the proper size of the tables
*/
virtual void setBitRequirements() const {}
};
/** Predictor parameters */
const int blockSize;
const int pcshift;
const int threshold;
const int bias0;
const int bias1;
const int biasmostly0;
const int biasmostly1;
const int nbest;
const int tunebits;
const int hshift;
const unsigned long long int imli_mask1;
const unsigned long long int imli_mask4;
const unsigned long long int recencypos_mask;
const double fudge;
const int n_sign_bits;
const int pcbit;
const int decay;
const unsigned int record_mask;
const bool hash_taken;
const bool tuneonly;
const int extra_rounds;
const int speed;
const int budgetbits;
const bool speculative_update;
/** Transfer function for 6-width tables */
static int xlat[];
/** Transfer function for 5-width tables */
static int xlat4[];
/** History data is kept for each thread */
struct ThreadData
{
ThreadData(int num_filter, int n_local_histories,
int local_history_length, int assoc,
const std::vector<std::vector<int>> &blurrypath_bits,
int path_length, int ghist_length, int block_size,
const std::vector<std::vector<std::vector<bool>>> &acyclic_bits,
const std::vector<int> &modhist_indices,
const std::vector<int> &modhist_lengths,
const std::vector<int> &modpath_indices,
const std::vector<int> &modpath_lengths,
const std::vector<int> &table_sizes, int n_sign_bits);
std::vector<FilterEntry> filterTable;
std::vector<std::vector<bool>> acyclic_histories;
std::vector<std::vector<unsigned int>> acyclic2_histories;
void updateAcyclic(bool hashed_taken, unsigned int hpc) {
for (int i = 0; i < acyclic_histories.size(); i += 1) {
if (acyclic_histories[i].size() > 0) {
acyclic_histories[i][hpc%(i+2)] = hashed_taken;
acyclic2_histories[i][hpc%(i+2)] = hpc;
}
}
}
std::vector<std::vector<unsigned int>> blurrypath_histories;
std::vector<unsigned int> ghist_words;
std::vector<std::vector<unsigned short int>> modpath_histories;
std::vector<std::vector<bool>> mod_histories;
std::vector<unsigned short int> path_history;
std::vector<unsigned int> imli_counter;
LocalHistories localHistories;
std::vector<unsigned int short> recency_stack;
void insertRecency(unsigned int pc, int assoc) {
int i = 0;
for (i = 0; i < assoc; i += 1) {
if (recency_stack[i] == pc) {
break;
}
}
if (i == assoc) {
i = assoc-1;
recency_stack[i] = pc;
}
int j;
unsigned int b = recency_stack[i];
for (j = i; j >= 1; j -= 1) {
recency_stack[j] = recency_stack[j-1];
}
recency_stack[0] = b;
}
bool last_ghist_bit;
int occupancy;
std::vector<int> mpreds;
std::vector<std::vector<short int>> tables;
std::vector<std::vector<std::array<bool, 2>>> sign_bits;
};
std::vector<ThreadData *> threadData;
/** Predictor tables */
std::vector<HistorySpec *> specs;
std::vector<int> table_sizes;
/** runtime values and data used to count the size in bits */
bool doing_local;
bool doing_recency;
int assoc;
int ghist_length;
int modghist_length;
int path_length;
int thresholdCounter;
int theta;
int extrabits;
std::vector<int> imli_counter_bits;
std::vector<int> modhist_indices;
std::vector<int> modhist_lengths;
std::vector<int> modpath_indices;
std::vector<int> modpath_lengths;
std::vector<std::vector<int>> blurrypath_bits;
std::vector<std::vector<std::vector<bool>>> acyclic_bits;
/** Auxiliary function for MODHIST and GHISTMODPATH features */
void insertModhistSpec(int p1, int p2) {
int j = insert(modhist_indices, p1);
if (modhist_lengths.size() < (j + 1)) {
modhist_lengths.resize(j + 1);
}
if (modhist_lengths[j] < p2 + 1) {
modhist_lengths[j] = p2 + 1;
}
if (p2 >= modghist_length) {
modghist_length = p2 + 1;
}
}
/** Auxiliary function for MODPATH and GHISTMODPATH features */
void insertModpathSpec(int p1, int p2) {
int j = insert(modpath_indices, p1);
if (modpath_lengths.size() < (j + 1)) {
modpath_lengths.resize(j + 1);
}
if (modpath_lengths[j] < p2 + 1) {
modpath_lengths[j] = p2 + 1;
}
if (p2 >= path_length) {
path_length = p2 + 1;
}
}
/** Auxiliary function used by insertModhistSpec and insertModpathSpec*/
int insert(std::vector<int> &v, int x)
{
for (int i = 0; i < v.size(); i += 1) {
if (v[i] == x) {
return i;
}
}
v.push_back(x);
return v.size()-1;
}
/**
* Computes the size in bits of the structures needed to keep track
* of the history and the predictor tables and assigns the sizes of
* those tables that did not had their size specified.
* @param num_filter_entries number of entries of the filter
* @param nlocal_histories number of local history entries
* @param local_history_length size of each local history entry
* @param ignore_path_size ignore the path length storage
*/
void computeBits(int num_filter_entries, int nlocal_histories,
int local_history_length, bool ignore_path_size);
/**
* Creates the tables of the predictor
*/
virtual void createSpecs() = 0;
/**
* Get the position index of a predictor table
* @param tid Thread ID of the branch
* @param bi branch informaiton data
* @param spec predictor table
* @param index integer index of the predictor table
* @result index to access the predictor table
*/
unsigned int getIndex(ThreadID tid, const MPPBranchInfo &bi,
const HistorySpec &spec, int index) const;
/**
* Finds the best subset of features to use in case of a low-confidence
* branch, returns the result as an ordered vector of the indices to the
* predictor tables
* @param tid Thread ID of the branch
* @param vector to write the ordered list of indices of the best tables
*/
void findBest(ThreadID tid, std::vector<int> &best_preds) const;
/**
* Computes the output of the predictor for a given branch and the
* resulting best value in case the prediction has low confidence
* @param tid Thread ID of the branch
* @param bi branch informaiton data
* @return resulting sum for low-confidence branch
*/
int computeOutput(ThreadID tid, MPPBranchInfo &bi);
/**
* Trains the branch predictor with the given branch and direction
* @param tid Thread ID of the branch
* @param bi branch informaiton data
* @param taken whether the branch was taken
*/
void train(ThreadID tid, MPPBranchInfo &bi, bool taken);
/**
* Auxiliary function to increase a table counter depending on the
* direction of the branch
* @param taken whether the branch was taken
* @param sign current sign of the table
* @param c current value of the table
* @param max_weight maximum value of the counter
*/
void satIncDec(bool taken, bool &sign, int &c, int max_weight) const;
/** Add a table spec to the prefetcher */
void addSpec(HistorySpec *spec)
{
specs.push_back(spec);
}
/** Available features */
class GHIST : public HistorySpec
{
public:
GHIST(int p1, int p2, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, 0, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
return hash(mpp.threadData[tid]->ghist_words, mpp.blockSize, p1,
p2);
}
static unsigned int hash(const std::vector<unsigned int> &ghist_words,
int block_size, int start_pos, int end_pos)
{
int a = start_pos;
int b = end_pos;
unsigned int x = 0;
// am is the next multiple of block_size after a
int am = (((a/block_size)*block_size)+block_size);
// bm is the previous multiple of block_size before b
int bm = (b/block_size)*block_size;
// the 0th bit of ghist_words[a/block_size] is the most recent bit.
// so the number of bits between a and am is the number to shift
// right?
// start out x as remainder bits from the beginning:
// x = [ . . . . . b b b b b ]
x += ghist_words[a / block_size] >> (a-am);
// add in bits from the middle
for (int i=am; i<bm; i+=block_size) {
x += ghist_words[i / block_size];
}
// add in remainder bits from end:
// x += [ b b b b b . . . . . ]
unsigned int y = ghist_words[bm / block_size] & ((1<<(b - bm))-1);
x += y << (block_size - (b - bm));
return x;
}
void setBitRequirements() const override
{
if (mpp.ghist_length <= p2) {
mpp.ghist_length = p2 + 1;
}
}
};
class ACYCLIC : public HistorySpec
{
public:
ACYCLIC(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int a = p1;
int shift = p2;
int style = p3;
std::vector<std::vector<bool>> &acyclic_histories =
mpp.threadData[tid]->acyclic_histories;
std::vector<std::vector<unsigned int>> &acyclic2_histories =
mpp.threadData[tid]->acyclic2_histories;
unsigned int x = 0;
if (style == -1) {
unsigned int k = 0;
for (int i = 0; i < a + 2; i += 1) {
x ^= acyclic_histories[a][i] << k;
k += 1;
k %= mpp.blockSize;
}
} else {
for (int i = 0; i < a + 2; i += 1) {
x <<= shift;
x += acyclic2_histories[a][i];
}
}
return x;
}
void setBitRequirements() const override
{
if (mpp.acyclic_bits.size() < (p1 + 1)) {
mpp.acyclic_bits.resize(p1 + 1);
}
if (mpp.acyclic_bits[p1].size() < (p1 + 2)) {
mpp.acyclic_bits[p1].resize(p1 + 2, std::vector<bool>(2));
}
for (int j = 0; j < p1 + 2; j += 1) {
mpp.acyclic_bits[p1][j][!p3] = true;
}
}
};
class MODHIST : public HistorySpec
{
public:
MODHIST(int p1, int p2, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, 0, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int a = p1;
int b = p2;
std::vector<std::vector<bool>> &mod_histories =
mpp.threadData[tid]->mod_histories;
unsigned int x = 0, k = 0;
for (int i = 0; i < b; i += 1) {
x ^= mod_histories[a][i] << k;
k += 1;
k %= mpp.blockSize;
}
return x;
}
void setBitRequirements() const override
{
mpp.insertModhistSpec(p1, p2);
}
};
class BIAS : public HistorySpec
{
public:
BIAS(double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(0, 0, 0, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
return 0;
}
};
class RECENCY : public HistorySpec
{
public:
RECENCY(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int depth = p1;
int shift = p2;
int style = p3;
std::vector<unsigned int short> &recency_stack =
mpp.threadData[tid]->recency_stack;
if (style == -1) {
unsigned int x = 0;
for (int i = 0; i < depth; i += 1) {
x <<= shift;
x += recency_stack[i];
}
return x;
} else {
unsigned int x = 0, k = 0;
for (int i = 0; i < depth; i += 1) {
x ^= (!!(recency_stack[i] & (1 << shift))) << k;
k += 1;
k %= mpp.blockSize;
}
return x;
}
}
void setBitRequirements() const override
{
if (mpp.assoc < p1) {
mpp.assoc = p1;
}
mpp.doing_recency = true;
}
};
class IMLI : public HistorySpec
{
public:
IMLI(int p1, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, 0, 0, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
assert(p1 >= 1);
assert(p1 <= 4);
return mpp.threadData[tid]->imli_counter[p1-1];
}
void setBitRequirements() const override
{
mpp.imli_counter_bits[p1 - 1] = 32;
}
};
class PATH : public HistorySpec
{
public:
PATH(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int depth = p1;
int shift = p2;
int style = p3;
std::vector<unsigned short int> &path_history =
mpp.threadData[tid]->path_history;
if (style == -1) {
unsigned int x = 0;
for (int i = 0; i < depth; i += 1) {
x <<= shift;
x += path_history[i];
}
return x;
} else {
unsigned int x = 0;
int bm = (depth / mpp.blockSize) * mpp.blockSize;
for (int i = 0; i < bm; i += mpp.blockSize) {
for (int j = 0; j < mpp.blockSize; j += 1) {
x ^= (!!(path_history[i + j] & (1 << shift))) << j;
}
}
int k = 0;
for (int i = bm; i < depth; i += 1) {
x ^= (!!(path_history[i] & (1 << shift))) << k++;
}
return x;
}
}
void setBitRequirements() const override
{
if (mpp.path_length <= p1) {
mpp.path_length = p1 + 1;
}
}
};
class LOCAL : public HistorySpec
{
public:
LOCAL(int p1, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, 0, 0, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
unsigned int x = mpp.threadData[tid]->localHistories[pc];
if (p1 != -1) {
x &= ((1 << p1) - 1);
}
return x;
}
void setBitRequirements() const override
{
mpp.doing_local = true;
}
};
class MODPATH : public HistorySpec
{
public:
MODPATH(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int a = p1;
int depth = p2;
int shift = p3;
unsigned int x = 0;
for (int i=0; i<depth; i += 1) {
x <<= shift;
x += mpp.threadData[tid]->modpath_histories[a][i];
}
return x;
}
void setBitRequirements() const override
{
mpp.insertModpathSpec(p1, p2);
}
};
class GHISTPATH : public HistorySpec
{
public:
GHISTPATH(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int depth = p1;
int shift = p2;
int style = p3;
std::vector<unsigned int> &ghist_words =
mpp.threadData[tid]->ghist_words;
std::vector<unsigned short int> &path_history =
mpp.threadData[tid]->path_history;
if (style == -1) {
unsigned int x = 0;
int bm = (depth / mpp.blockSize) * mpp.blockSize;
unsigned int w;
for (int i = 0; i < bm; i += mpp.blockSize) {
w = ghist_words[i / mpp.blockSize];
for (int j = 0; j < mpp.blockSize; j += 1) {
x <<= shift;
x += (path_history[i + j] << 1) | (w & 1);
w >>= 1;
}
}
w = ghist_words[bm / mpp.blockSize];
for (int i = bm; i < depth; i += 1) {
x <<= shift;
x += (path_history[i] << 1) | (w & 1);
w >>= 1;
}
return x;
} else {
unsigned int x = 0;
int bm = (depth / mpp.blockSize) * mpp.blockSize;
unsigned int w = 0;
for (int i = 0; i < bm; i += mpp.blockSize) {
w = ghist_words[i / mpp.blockSize];
for (int j = 0; j < mpp.blockSize; j += 1) {
x ^= (!!(path_history[i + j] & (1 << shift))) << j;
x ^= (w & 1) << j;
w >>= 1;
}
}
w = ghist_words[bm/mpp.blockSize];
int k = 0;
for (int i = bm; i < depth; i += 1) {
x ^= (!!(path_history[i] & (1 << shift))) << k;
x ^= (w & 1) << k;
w >>= 1;
k += 1;
}
return x;
}
}
void setBitRequirements() const override
{
if (mpp.ghist_length <= p1) {
mpp.ghist_length = p1 + 1;
}
if (mpp.path_length <= p1) {
mpp.path_length = p1 + 1;
}
}
};
class GHISTMODPATH : public HistorySpec
{
public:
GHISTMODPATH(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int a = p1;
int depth = p2;
int shift = p3;
std::vector<std::vector<unsigned short int>> &modpath_histories =
mpp.threadData[tid]->modpath_histories;
std::vector<std::vector<bool>> &mod_histories =
mpp.threadData[tid]->mod_histories;
unsigned int x = 0;
for (int i = 0; i < depth; i += 1) {
x <<= shift;
x += (modpath_histories[a][i] << 1) | mod_histories[a][i];
}
return x;
}
void setBitRequirements() const override
{
mpp.insertModhistSpec(p1, p2);
mpp.insertModpathSpec(p1, p2);
}
};
class BLURRYPATH : public HistorySpec
{
public:
BLURRYPATH(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int scale = p1;
int depth = p2;
int shiftdelta = p3;
if (shiftdelta == -1) shiftdelta = 0;
int sdint = shiftdelta >> 2;
int sdfrac = shiftdelta & 3;
unsigned int x = 0;
int shift = 0;
int count = 0;
for (int i = 0; i < depth; i += 1) {
x += mpp.threadData[tid]->blurrypath_histories[scale][i] >>
shift;
count += 1;
if (count == sdfrac) {
shift += sdint;
count = 0;
}
}
return x;
}
void setBitRequirements() const override
{
if (mpp.blurrypath_bits.size() < (p1 + 1)) {
mpp.blurrypath_bits.resize(p1 + 1);
}
if (mpp.blurrypath_bits[p1].size() < p2) {
mpp.blurrypath_bits[p1].resize(p2);
}
for (int j = 0; j < p2; j += 1) {
mpp.blurrypath_bits[p1][j] = 32 - p1;
}
}
};
class RECENCYPOS : public HistorySpec
{
public:
RECENCYPOS(int p1, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, 0, 0, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
return hash(mpp.threadData[tid]->recency_stack, mpp.table_sizes,
pc2, p1, t);
}
static unsigned int hash(
const std::vector<unsigned int short> &recency_stack,
const std::vector<int> &table_sizes, unsigned short int pc, int l,
int t)
{
// search for the PC
for (int i = 0; i < l; i += 1) {
if (recency_stack[i] == pc) {
return i * table_sizes[t] / l;
}
}
// return last index in table on a miss
return table_sizes[t] - 1;
}
void setBitRequirements() const override
{
if (mpp.assoc < p1) {
mpp.assoc = p1;
}
mpp.doing_recency = true;
}
};
class SGHISTPATH : public HistorySpec
{
public:
SGHISTPATH(int p1, int p2, int p3, double coeff, int size, int width,
MultiperspectivePerceptron &mpp)
: HistorySpec(p1, p2, p3, coeff, size, width, mpp)
{}
unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
override
{
int a = p1;
int b = p2;
int shift = p3;
std::vector<unsigned int> &ghist_words =
mpp.threadData[tid]->ghist_words;
std::vector<unsigned short int> &path_history =
mpp.threadData[tid]->path_history;
unsigned int x = 0;
int bm = (b / mpp.blockSize) * mpp.blockSize;
unsigned int w;
for (int i = a; i < bm; i += mpp.blockSize) {
w = ghist_words[i / mpp.blockSize];
for (int j = 0; j < mpp.blockSize; j += 1) {
x <<= shift;
x += (path_history[i+j] << 1) | (w & 1);
w >>= 1;
}
}
w = ghist_words[bm / mpp.blockSize];
for (int i = bm; i < b; i += 1) {
x <<= shift;
x += (path_history[i] << 1) | (w & 1);
w >>= 1;
}
return x;
}
};
public:
MultiperspectivePerceptron(const MultiperspectivePerceptronParams &params);
/**
* Sets the starting number of storage bits to compute the number of
* table entries
* @param bits number of bits used
*/
void setExtraBits(int bits);
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;
};
} // namespace branch_prediction
} // namespace gem5
#endif//__CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__