| /* |
| * 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 ¶ms); |
| |
| /** |
| * 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__ |