| /* | |
| * 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" | |
| 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 = MaxAddr) override; | |
| void btbUpdate(ThreadID tid, Addr branch_addr, void* &bp_history) override; | |
| }; | |
| #endif//__CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__ |