1/*
2 * Copyright 2019 Texas A&M University
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 *    this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its
15 *    contributors may be used to endorse or promote products derived from this
16 *    software without specific prior written permission.
17 *
18 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 *  Author: Daniel A. Jiménez
31 *  Adapted to gem5 by: Javier Bueno Hedo
32 *
33 */
34
35/*
36 * Multiperspective Perceptron Predictor (by Daniel A. Jiménez)
37 */
38
39#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__
40#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__
41
42#include <array>
43#include <vector>
44
45#include "cpu/pred/bpred_unit.hh"
46#include "params/MultiperspectivePerceptron.hh"
47
48class MultiperspectivePerceptron : public BPredUnit
49{
50  protected:
51    /**
52     * Branch information data
53     */
54    class MPPBranchInfo {
55        /** pc of the branch */
56        const unsigned int pc;
57        /** pc of the branch, shifted 2 bits to the right */
58        const unsigned short int pc2;
59        /** pc of the branch, hashed */
60        const unsigned short int hpc;
61        /** Whether this is a conditional branch */
62        const bool condBranch;
63
64        /**
65         * PC Hash functions
66         */
67        static inline unsigned int hash1(unsigned int a)
68        {
69            a = (a ^ 0xdeadbeef) + (a<<4);
70            a = a ^ (a>>10);
71            a = a + (a<<7);
72            a = a ^ (a>>13);
73            return a;
74        }
75
76        static inline unsigned int hash2(unsigned int key)
77        {
78            int c2 = 0x27d4eb2d; // a prime or an odd constant
79            key = (key ^ 61) ^ (key >> 16);
80            key = key + (key << 3);
81            key = key ^ (key >> 4);
82            key = key * c2;
83            key = key ^ (key >> 15);
84            return key;
85        }
86
87        static inline unsigned int hash(unsigned int key, unsigned int i)
88        {
89            return hash2(key) * i + hash1(key);
90        }
91
92        static inline unsigned int hashPC(unsigned int pc, int pcshift)
93        {
94            if (pcshift < 0) {
95                return hash(pc, -pcshift);
96            } else if (pcshift < 11) {
97                unsigned int x = pc;
98                x ^= (pc >> pcshift);
99                return x;
100            } else {
101                return pc >> (pcshift-11);
102            }
103        }
104
105      public:
106        /** Whether this branch has been filtered by the prefetcher */
107        bool filtered;
108        /** Result of the prediction (true is taken) */
109        bool prediction;
110        /** Score of the perceptron */
111        int yout;
112
113        MPPBranchInfo(Addr _pc, int pcshift, bool cb) : pc((unsigned int)_pc),
114        pc2(pc >> 2), hpc(hashPC(pc, pcshift)), condBranch(cb),
115        filtered(false), prediction(false), yout(0)
116        { }
117
118        unsigned int getPC() const
119        {
120            return pc;
121        }
122        unsigned short int getPC2() const
123        {
124            return pc2;
125        }
126        unsigned short int getHPC() const
127        {
128            return hpc;
129        }
130        unsigned int getHashFilter(bool last_ghist_bit) const
131        {
132            return last_ghist_bit ^ hpc;
133        }
134        bool isUnconditional() const
135        {
136            return !condBranch;
137        }
138    };
139
140    /**
141     * Entry of the branch filter
142     */
143    struct FilterEntry {
144        /** Has this branch been taken at least once? */
145        bool seenTaken;
146        /** Has this branch been not taken at least once? */
147        bool seenUntaken;
148
149        FilterEntry() : seenTaken(false), seenUntaken(false) {}
150
151        /** Whether this branch has always been observed as not taken */
152        bool alwaysNotTakenSoFar() const {
153            return seenUntaken & !seenTaken;
154        }
155        /** Whether this branch has always been observed as taken */
156        bool alwaysTakenSoFar() const {
157            return seenTaken & !seenUntaken;
158        }
159        /** Whether this branch has been observed before */
160        bool neverSeen() const {
161            return !seenTaken && !seenUntaken;
162        }
163    };
164
165
166    /**
167     * Local history entries, each enty contains the history of directions
168     * taken by a given branch.
169     */
170    class LocalHistories {
171        /** The array of histories */
172        std::vector<unsigned int> localHistories;
173        /** Size in bits of each history entry */
174        const int localHistoryLength;
175
176        /** Index function given the pc of the branch */
177        unsigned int index(Addr pc) const {
178            return (pc >> 2) % localHistories.size();
179        }
180        public:
181        LocalHistories(int nlocal_histories, int histo_len) :
182            localHistories(nlocal_histories), localHistoryLength(histo_len) {}
183
184        /** Obtains the local history entry of a given branch */
185        unsigned int operator[](Addr pc) const
186        {
187            return localHistories[index(pc)];
188        }
189
190        /** Adds a history bit to the local history entry of a given branch */
191        void update(Addr pc, bool value)
192        {
193            assert(localHistories.size() > 0);
194            unsigned int &pos = localHistories[index(pc)];
195            pos <<= 1;
196            pos |= value;
197            pos &= ((1<<localHistoryLength)-1);
198        }
199
200        /** Returns the number of bits of each local history entry */
201        int getLocalHistoryLength() const
202        {
203            return localHistoryLength;
204        }
205
206        /** Size in bits required by all history entries */
207        int getSize() const
208        {
209            return localHistoryLength * localHistories.size();
210        }
211    };
212
213    /**
214     * Base class to implement the predictor tables.
215     */
216    struct HistorySpec {
217        /** First parameter */
218        const int p1;
219        /** Second parameter */
220        const int p2;
221        /** Third parameter */
222        const int p3;
223        /** Coefficient of the feature, models the accuracy of the feature */
224        const double coeff;
225        /** Pre-assigned size in bits assigned to this feature */
226        const int size;
227        /** Width of the table in bits  */
228        const int width;
229        /** Reference to the branch predictor class */
230        MultiperspectivePerceptron &mpp;
231
232        HistorySpec(int _p1, int _p2, int _p3, double _coeff, int _size,
233                int _width, MultiperspectivePerceptron &_mpp) : p1(_p1),
234        p2(_p2), p3(_p3), coeff(_coeff), size(_size), width(_width),
235        mpp(_mpp)
236        {}
237
238        /**
239         * Gets the hash to index the table, using the pc of the branch,
240         * and the index of the table.
241         * @param tid Thread ID of the branch
242         * @param pc address of the branch
243         * @param pc2 address of the branch shifted 2 bits to the right
244         * @param t integer index of the table
245         * @result resulting hash value that will be used to index the table
246         */
247        virtual unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t)
248            const = 0;
249        /**
250         * Sets the size requirements of the table, used when initializing
251         * to set the proper size of the tables
252         */
253        virtual void setBitRequirements() const {}
254    };
255
256    /** Predictor parameters */
257    const int blockSize;
258    const int pcshift;
259    const int threshold;
260    const int bias0;
261    const int bias1;
262    const int biasmostly0;
263    const int biasmostly1;
264    const int nbest;
265    const int tunebits;
266    const int hshift;
267    const unsigned long long int imli_mask1;
268    const unsigned long long int imli_mask4;
269    const unsigned long long int recencypos_mask;
270    const double fudge;
271    const int n_sign_bits;
272    const int pcbit;
273    const int decay;
274    const unsigned int record_mask;
275    const bool hash_taken;
276    const bool tuneonly;
277    const int extra_rounds;
278    const int speed;
279    const int budgetbits;
280    const bool speculative_update;
281
282    /** Transfer function for 6-width tables */
283    static int xlat[];
284    /** Transfer function for 5-width tables */
285    static int xlat4[];
286
287    /** History data is kept for each thread */
288    struct ThreadData {
289        ThreadData(int num_filter, int n_local_histories,
290            int local_history_length, int assoc,
291            const std::vector<std::vector<int>> &blurrypath_bits,
292            int path_length, int ghist_length, int block_size,
293            const std::vector<std::vector<std::vector<bool>>> &acyclic_bits,
294            const std::vector<int> &modhist_indices,
295            const std::vector<int> &modhist_lengths,
296            const std::vector<int> &modpath_indices,
297            const std::vector<int> &modpath_lengths,
298            const std::vector<int> &table_sizes, int n_sign_bits);
299
300        std::vector<FilterEntry> filterTable;
301        std::vector<std::vector<bool>> acyclic_histories;
302        std::vector<std::vector<unsigned int>> acyclic2_histories;
303
304        void updateAcyclic(bool hashed_taken, unsigned int hpc) {
305            for (int i = 0; i < acyclic_histories.size(); i += 1) {
306                if (acyclic_histories[i].size() > 0) {
307                    acyclic_histories[i][hpc%(i+2)] = hashed_taken;
308                    acyclic2_histories[i][hpc%(i+2)] = hpc;
309                }
310            }
311        }
312
313        std::vector<std::vector<unsigned int>> blurrypath_histories;
314        std::vector<unsigned int> ghist_words;
315        std::vector<std::vector<unsigned short int>> modpath_histories;
316        std::vector<std::vector<bool>> mod_histories;
317        std::vector<unsigned short int> path_history;
318        std::vector<unsigned int> imli_counter;
319        LocalHistories localHistories;
320        std::vector<unsigned int short> recency_stack;
321
322        void insertRecency(unsigned int pc, int assoc) {
323            int i = 0;
324            for (i = 0; i < assoc; i += 1) {
325                if (recency_stack[i] == pc) {
326                    break;
327                }
328            }
329            if (i == assoc) {
330                i = assoc-1;
331                recency_stack[i] = pc;
332            }
333            int j;
334            unsigned int b = recency_stack[i];
335            for (j = i; j >= 1; j -= 1) {
336                recency_stack[j] = recency_stack[j-1];
337            }
338            recency_stack[0] = b;
339        }
340
341        bool last_ghist_bit;
342        int occupancy;
343
344        std::vector<int> mpreds;
345        std::vector<std::vector<short int>> tables;
346        std::vector<std::vector<std::array<bool, 2>>> sign_bits;
347    };
348    std::vector<ThreadData *> threadData;
349
350    /** Predictor tables */
351    std::vector<HistorySpec *> specs;
352    std::vector<int> table_sizes;
353
354    /** runtime values and data used to count the size in bits */
355    bool doing_local;
356    bool doing_recency;
357    int assoc;
358    int ghist_length;
359    int modghist_length;
360    int path_length;
361    int thresholdCounter;
362    int theta;
363    int extrabits;
364    std::vector<int> imli_counter_bits;
365    std::vector<int> modhist_indices;
366    std::vector<int> modhist_lengths;
367    std::vector<int> modpath_indices;
368    std::vector<int> modpath_lengths;
369    std::vector<std::vector<int>> blurrypath_bits;
370    std::vector<std::vector<std::vector<bool>>> acyclic_bits;
371
372    /** Auxiliary function for MODHIST and GHISTMODPATH features */
373    void insertModhistSpec(int p1, int p2) {
374        int j = insert(modhist_indices, p1);
375        if (modhist_lengths.size() < (j + 1)) {
376            modhist_lengths.resize(j + 1);
377        }
378        if (modhist_lengths[j] < p2 + 1) {
379            modhist_lengths[j] = p2 + 1;
380        }
381        if (p2 >= modghist_length) {
382            modghist_length = p2 + 1;
383        }
384    }
385
386    /** Auxiliary function for MODPATH and GHISTMODPATH features */
387    void insertModpathSpec(int p1, int p2) {
388        int j = insert(modpath_indices, p1);
389        if (modpath_lengths.size() < (j + 1)) {
390            modpath_lengths.resize(j + 1);
391        }
392        if (modpath_lengths[j] < p2 + 1) {
393            modpath_lengths[j] = p2 + 1;
394        }
395        if (p2 >= path_length) {
396            path_length = p2 + 1;
397        }
398    }
399
400    /** Auxiliary function used by insertModhistSpec and insertModpathSpec*/
401    int insert(std::vector<int> &v, int x)
402    {
403        for (int i = 0; i < v.size(); i += 1) {
404            if (v[i] == x) {
405                return i;
406            }
407        }
408        v.push_back(x);
409        return v.size()-1;
410    }
411
412    /**
413     * Computes the size in bits of the structures needed to keep track
414     * of the history and the predictor tables and assigns the sizes of
415     * those tables that did not had their size specified.
416     * @param num_filter_entries number of entries of the filter
417     * @param nlocal_histories number of local history entries
418     * @param local_history_length size of each local history entry
419     * @param ignore_path_size ignore the path length storage
420     */
421    void computeBits(int num_filter_entries, int nlocal_histories,
422            int local_history_length, bool ignore_path_size);
423
424    /**
425     * Creates the tables of the predictor
426     */
427    virtual void createSpecs() = 0;
428
429    /**
430     * Get the position index of a predictor table
431     * @param tid Thread ID of the branch
432     * @param bi branch informaiton data
433     * @param spec predictor table
434     * @param index integer index of the predictor table
435     * @result index to access the predictor table
436     */
437    unsigned int getIndex(ThreadID tid, const MPPBranchInfo &bi,
438            const HistorySpec &spec, int index) const;
439    /**
440     * Finds the best subset of features to use in case of a low-confidence
441     * branch, returns the result as an ordered vector of the indices to the
442     * predictor tables
443     * @param tid Thread ID of the branch
444     * @param vector to write the ordered list of indices of the best tables
445     */
446    void findBest(ThreadID tid, std::vector<int> &best_preds) const;
447
448    /**
449     * Computes the output of the predictor for a given branch and the
450     * resulting best value in case the prediction has low confidence
451     * @param tid Thread ID of the branch
452     * @param bi branch informaiton data
453     * @return resulting sum for low-confidence branch
454     */
455    int computeOutput(ThreadID tid, MPPBranchInfo &bi);
456
457    /**
458     * Trains the branch predictor with the given branch and direction
459     * @param tid Thread ID of the branch
460     * @param bi branch informaiton data
461     * @param taken whether the branch was taken
462     */
463    void train(ThreadID tid, MPPBranchInfo &bi, bool taken);
464
465    /**
466     * Auxiliary function to increase a table counter depending on the
467     * direction of the branch
468     * @param taken whether the branch was taken
469     * @param sign current sign of the table
470     * @param c current value of the table
471     * @param max_weight maximum value of the counter
472     */
473    void satIncDec(bool taken, bool &sign, int &c, int max_weight) const;
474
475    /** Add a table spec to the prefetcher */
476    void addSpec(HistorySpec *spec)
477    {
478        specs.push_back(spec);
479    }
480
481    /** Available features */
482
483    class GHIST : public HistorySpec {
484      public:
485        GHIST(int p1, int p2, double coeff, int size, int width,
486                MultiperspectivePerceptron &mpp)
487            : HistorySpec(p1, p2, 0, coeff, size, width, mpp)
488        {}
489
490        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
491            override
492        {
493            return hash(mpp.threadData[tid]->ghist_words, mpp.blockSize, p1,
494                        p2);
495        }
496
497        static unsigned int hash(const std::vector<unsigned int> &ghist_words,
498                int block_size, int start_pos, int end_pos)
499        {
500            int a = start_pos;
501            int b = end_pos;
502
503            unsigned int x = 0;
504            // am is the next multiple of block_size after a
505            int am = (((a/block_size)*block_size)+block_size);
506            // bm is the previous multiple of block_size before b
507            int bm = (b/block_size)*block_size;
508
509            // the 0th bit of ghist_words[a/block_size] is the most recent bit.
510            // so the number of bits between a and am is the number to shift
511            // right?
512
513            // start out x as remainder bits from the beginning:
514            // x = [ . . . . . b b b b b ]
515            x += ghist_words[a / block_size] >> (a-am);
516            // add in bits from the middle
517            for (int i=am; i<bm; i+=block_size) {
518                x += ghist_words[i / block_size];
519            }
520            // add in remainder bits from end:
521            // x += [ b b b b b . . . . . ]
522            unsigned int y = ghist_words[bm / block_size] & ((1<<(b - bm))-1);
523            x += y << (block_size - (b - bm));
524            return x;
525        }
526        void setBitRequirements() const override
527        {
528            if (mpp.ghist_length <= p2) {
529                mpp.ghist_length = p2 + 1;
530            }
531        }
532    };
533
534    class ACYCLIC : public HistorySpec {
535      public:
536        ACYCLIC(int p1, int p2, int p3, double coeff, int size, int width,
537                MultiperspectivePerceptron &mpp)
538            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
539        {}
540
541        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
542            override
543        {
544            int a = p1;
545            int shift = p2;
546            int style = p3;
547            std::vector<std::vector<bool>> &acyclic_histories =
548                mpp.threadData[tid]->acyclic_histories;
549            std::vector<std::vector<unsigned int>> &acyclic2_histories =
550                mpp.threadData[tid]->acyclic2_histories;
551
552            unsigned int x = 0;
553            if (style == -1) {
554                unsigned int k = 0;
555                for (int i = 0; i < a + 2; i += 1) {
556                    x ^= acyclic_histories[a][i] << k;
557                    k += 1;
558                    k %= mpp.blockSize;
559                }
560            } else {
561                for (int i = 0; i < a + 2; i += 1) {
562                    x <<= shift;
563                    x += acyclic2_histories[a][i];
564                }
565            }
566            return x;
567        }
568        void setBitRequirements() const override
569        {
570            if (mpp.acyclic_bits.size() < (p1 + 1)) {
571                mpp.acyclic_bits.resize(p1 + 1);
572            }
573            if (mpp.acyclic_bits[p1].size() < (p1 + 2)) {
574                mpp.acyclic_bits[p1].resize(p1 + 2, std::vector<bool>(2));
575            }
576            for (int j = 0; j < p1 + 2; j += 1) {
577                mpp.acyclic_bits[p1][j][!p3] = true;
578            }
579        }
580    };
581
582    class MODHIST : public HistorySpec {
583      public:
584        MODHIST(int p1, int p2, double coeff, int size, int width,
585                MultiperspectivePerceptron &mpp)
586            : HistorySpec(p1, p2, 0, coeff, size, width, mpp)
587        {}
588
589        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
590            override
591        {
592            int a = p1;
593            int b = p2;
594            std::vector<std::vector<bool>> &mod_histories =
595                mpp.threadData[tid]->mod_histories;
596
597            unsigned int x = 0, k = 0;
598            for (int i = 0; i < b; i += 1) {
599                x ^= mod_histories[a][i] << k;
600                k += 1;
601                k %= mpp.blockSize;
602            }
603            return x;
604        }
605        void setBitRequirements() const override
606        {
607            mpp.insertModhistSpec(p1, p2);
608        }
609    };
610
611    class BIAS : public HistorySpec {
612      public:
613        BIAS(double coeff, int size, int width,
614                MultiperspectivePerceptron &mpp)
615            : HistorySpec(0, 0, 0, coeff, size, width, mpp)
616        {}
617
618        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
619            override
620        {
621            return 0;
622        }
623    };
624
625
626    class RECENCY : public HistorySpec {
627      public:
628        RECENCY(int p1, int p2, int p3, double coeff, int size, int width,
629                MultiperspectivePerceptron &mpp)
630            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
631        {}
632
633        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
634            override
635        {
636            int depth = p1;
637            int shift = p2;
638            int style = p3;
639            std::vector<unsigned int short> &recency_stack =
640                mpp.threadData[tid]->recency_stack;
641
642            if (style == -1) {
643                unsigned int x = 0;
644                for (int i = 0; i < depth; i += 1) {
645                    x <<= shift;
646                    x += recency_stack[i];
647                }
648                return x;
649            } else {
650                unsigned int x = 0, k = 0;
651                for (int i = 0; i < depth; i += 1) {
652                    x ^= (!!(recency_stack[i] & (1 << shift))) << k;
653                    k += 1;
654                    k %= mpp.blockSize;
655                }
656                return x;
657            }
658        }
659        void setBitRequirements() const override
660        {
661            if (mpp.assoc < p1) {
662                mpp.assoc = p1;
663            }
664            mpp.doing_recency = true;
665        }
666    };
667
668    class IMLI : public HistorySpec {
669        public:
670            IMLI(int p1, double coeff, int size, int width,
671                    MultiperspectivePerceptron &mpp)
672                : HistorySpec(p1, 0, 0, coeff, size, width, mpp)
673            {}
674
675            unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
676                override
677                {
678                    assert(p1 >= 1);
679                    assert(p1 <= 4);
680                    return mpp.threadData[tid]->imli_counter[p1-1];
681                }
682
683            void setBitRequirements() const override
684            {
685                mpp.imli_counter_bits[p1 - 1] = 32;
686            }
687    };
688
689    class PATH : public HistorySpec {
690      public:
691        PATH(int p1, int p2, int p3, double coeff, int size, int width,
692                MultiperspectivePerceptron &mpp)
693            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
694        {}
695
696        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
697            override
698        {
699            int depth = p1;
700            int shift = p2;
701            int style = p3;
702            std::vector<unsigned short int> &path_history =
703                mpp.threadData[tid]->path_history;
704
705            if (style == -1) {
706                unsigned int x = 0;
707                for (int i = 0; i < depth; i += 1) {
708                    x <<= shift;
709                    x += path_history[i];
710                }
711                return x;
712            } else {
713                unsigned int x = 0;
714                int bm = (depth / mpp.blockSize) * mpp.blockSize;
715                for (int i = 0; i < bm; i += mpp.blockSize) {
716                    for (int j = 0; j < mpp.blockSize; j += 1) {
717                        x ^= (!!(path_history[i + j] & (1 << shift))) << j;
718                    }
719                }
720                int k = 0;
721                for (int i = bm; i < depth; i += 1) {
722                    x ^= (!!(path_history[i] & (1 << shift))) << k++;
723                }
724                return x;
725            }
726        }
727        void setBitRequirements() const override
728        {
729            if (mpp.path_length <= p1) {
730                mpp.path_length = p1 + 1;
731            }
732        }
733    };
734
735    class LOCAL : public HistorySpec {
736      public:
737        LOCAL(int p1, double coeff, int size, int width,
738                MultiperspectivePerceptron &mpp)
739            : HistorySpec(p1, 0, 0, coeff, size, width, mpp)
740        {}
741
742        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
743            override
744        {
745            unsigned int x = mpp.threadData[tid]->localHistories[pc];
746            if (p1 != -1) {
747                x &= ((1 << p1) - 1);
748            }
749            return x;
750        }
751        void setBitRequirements() const override
752        {
753            mpp.doing_local = true;
754        }
755    };
756
757    class MODPATH : public HistorySpec {
758      public:
759        MODPATH(int p1, int p2, int p3, double coeff, int size, int width,
760                MultiperspectivePerceptron &mpp)
761            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
762        {}
763
764        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
765            override
766        {
767            int a = p1;
768            int depth = p2;
769            int shift = p3;
770
771            unsigned int x = 0;
772            for (int i=0; i<depth; i += 1) {
773                x <<= shift;
774                x += mpp.threadData[tid]->modpath_histories[a][i];
775            }
776            return x;
777        }
778        void setBitRequirements() const override
779        {
780            mpp.insertModpathSpec(p1, p2);
781        }
782    };
783
784    class GHISTPATH : public HistorySpec {
785      public:
786        GHISTPATH(int p1, int p2, int p3, double coeff, int size, int width,
787                MultiperspectivePerceptron &mpp)
788            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
789        {}
790
791        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
792            override
793        {
794            int depth = p1;
795            int shift = p2;
796            int style = p3;
797            std::vector<unsigned int> &ghist_words =
798                mpp.threadData[tid]->ghist_words;
799            std::vector<unsigned short int> &path_history =
800                mpp.threadData[tid]->path_history;
801
802            if (style == -1) {
803                unsigned int x = 0;
804                int bm = (depth / mpp.blockSize) * mpp.blockSize;
805                unsigned int w;
806                for (int i = 0; i < bm; i += mpp.blockSize) {
807                    w = ghist_words[i / mpp.blockSize];
808                    for (int j = 0; j < mpp.blockSize; j += 1) {
809                        x <<= shift;
810                        x += (path_history[i + j] << 1) | (w & 1);
811                        w >>= 1;
812                    }
813                }
814                w = ghist_words[bm / mpp.blockSize];
815                for (int i = bm; i < depth; i += 1) {
816                    x <<= shift;
817                    x += (path_history[i] << 1) | (w & 1);
818                    w >>= 1;
819                }
820                return x;
821            } else {
822                unsigned int x = 0;
823                int bm = (depth / mpp.blockSize) * mpp.blockSize;
824                unsigned int w = 0;
825                for (int i = 0; i < bm; i += mpp.blockSize) {
826                    w = ghist_words[i / mpp.blockSize];
827                    for (int j = 0; j < mpp.blockSize; j += 1) {
828                        x ^= (!!(path_history[i + j] & (1 << shift))) << j;
829                        x ^= (w & 1) << j;
830                        w >>= 1;
831                    }
832                }
833                w = ghist_words[bm/mpp.blockSize];
834                int k = 0;
835                for (int i = bm; i < depth; i += 1) {
836                    x ^= (!!(path_history[i] & (1 << shift))) << k;
837                    x ^= (w & 1) << k;
838                    w >>= 1;
839                    k += 1;
840                }
841                return x;
842            }
843        }
844
845        void setBitRequirements() const override
846        {
847            if (mpp.ghist_length <= p1) {
848                mpp.ghist_length = p1 + 1;
849            }
850            if (mpp.path_length <= p1) {
851                mpp.path_length = p1 + 1;
852            }
853        }
854    };
855
856    class GHISTMODPATH : public HistorySpec {
857      public:
858        GHISTMODPATH(int p1, int p2, int p3, double coeff, int size, int width,
859                MultiperspectivePerceptron &mpp)
860            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
861        {}
862
863        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
864            override
865        {
866            int a = p1;
867            int depth = p2;
868            int shift = p3;
869            std::vector<std::vector<unsigned short int>> &modpath_histories =
870                mpp.threadData[tid]->modpath_histories;
871            std::vector<std::vector<bool>> &mod_histories =
872                mpp.threadData[tid]->mod_histories;
873
874            unsigned int x = 0;
875            for (int i = 0; i < depth; i += 1) {
876                x <<= shift;
877                x += (modpath_histories[a][i] << 1) | mod_histories[a][i];
878            }
879            return x;
880        }
881        void setBitRequirements() const override
882        {
883            mpp.insertModhistSpec(p1, p2);
884            mpp.insertModpathSpec(p1, p2);
885        }
886    };
887
888    class BLURRYPATH : public HistorySpec {
889      public:
890        BLURRYPATH(int p1, int p2, int p3, double coeff, int size, int width,
891                MultiperspectivePerceptron &mpp)
892            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
893        {}
894
895        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
896            override
897        {
898            int scale = p1;
899            int depth = p2;
900            int shiftdelta = p3;
901
902            if (shiftdelta == -1) shiftdelta = 0;
903            int sdint = shiftdelta >> 2;
904            int sdfrac = shiftdelta & 3;
905            unsigned int x = 0;
906            int shift = 0;
907            int count = 0;
908            for (int i = 0; i < depth; i += 1) {
909                x += mpp.threadData[tid]->blurrypath_histories[scale][i] >>
910                    shift;
911                count += 1;
912                if (count == sdfrac) {
913                    shift += sdint;
914                    count = 0;
915                }
916            }
917            return x;
918
919        }
920        void setBitRequirements() const override
921        {
922            if (mpp.blurrypath_bits.size() < (p1 + 1)) {
923                mpp.blurrypath_bits.resize(p1 + 1);
924            }
925            if (mpp.blurrypath_bits[p1].size() < p2) {
926                mpp.blurrypath_bits[p1].resize(p2);
927            }
928            for (int j = 0; j < p2; j += 1) {
929                mpp.blurrypath_bits[p1][j] = 32 - p1;
930            }
931        }
932    };
933
934    class RECENCYPOS : public HistorySpec {
935      public:
936        RECENCYPOS(int p1, double coeff, int size, int width,
937                MultiperspectivePerceptron &mpp)
938            : HistorySpec(p1, 0, 0, coeff, size, width, mpp)
939        {}
940
941        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
942            override
943        {
944            return hash(mpp.threadData[tid]->recency_stack, mpp.table_sizes,
945                    pc2, p1, t);
946        }
947
948        static unsigned int hash(
949            const std::vector<unsigned int short> &recency_stack,
950            const std::vector<int> &table_sizes, unsigned short int pc, int l,
951            int t)
952        {
953            // search for the PC
954
955            for (int i = 0; i < l; i += 1) {
956                if (recency_stack[i] == pc) {
957                    return i * table_sizes[t] / l;
958                }
959            }
960
961            // return last index in table on a miss
962
963            return table_sizes[t] - 1;
964        }
965
966        void setBitRequirements() const override
967        {
968            if (mpp.assoc < p1) {
969                mpp.assoc = p1;
970            }
971            mpp.doing_recency = true;
972        }
973    };
974
975    class SGHISTPATH : public HistorySpec {
976      public:
977        SGHISTPATH(int p1, int p2, int p3, double coeff, int size, int width,
978                MultiperspectivePerceptron &mpp)
979            : HistorySpec(p1, p2, p3, coeff, size, width, mpp)
980        {}
981
982        unsigned int getHash(ThreadID tid, Addr pc, Addr pc2, int t) const
983            override
984        {
985            int a = p1;
986            int b = p2;
987            int shift = p3;
988            std::vector<unsigned int> &ghist_words =
989                mpp.threadData[tid]->ghist_words;
990            std::vector<unsigned short int> &path_history =
991                mpp.threadData[tid]->path_history;
992
993            unsigned int x = 0;
994            int bm = (b / mpp.blockSize) * mpp.blockSize;
995            unsigned int w;
996            for (int i = a; i < bm; i += mpp.blockSize) {
997                w = ghist_words[i / mpp.blockSize];
998                for (int j = 0; j < mpp.blockSize; j += 1) {
999                    x <<= shift;
1000                    x += (path_history[i+j] << 1) | (w & 1);
1001                    w >>= 1;
1002                }
1003            }
1004            w = ghist_words[bm / mpp.blockSize];
1005            for (int i = bm; i < b; i += 1) {
1006                x <<= shift;
1007                x += (path_history[i] << 1) | (w & 1);
1008                w >>= 1;
1009            }
1010            return x;
1011        }
1012    };
1013
1014    public:
1015    MultiperspectivePerceptron(const MultiperspectivePerceptronParams *params);
1016
1017    /**
1018     * Sets the starting number of storage bits to compute the number of
1019     * table entries
1020     * @param bits number of bits used
1021     */
1022    void setExtraBits(int bits);
1023
1024    void init() override;
1025
1026    void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) override;
1027    void squash(ThreadID tid, void *bp_history) override;
1028    bool lookup(ThreadID tid, Addr instPC, void * &bp_history) override;
1029    void update(ThreadID tid, Addr instPC, bool taken,
1030            void *bp_history, bool squashed,
1031            const StaticInstPtr & inst,
1032            Addr corrTarget = MaxAddr) override;
1033    void btbUpdate(ThreadID tid, Addr branch_addr, void* &bp_history) override;
1034};
1035#endif//__CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_HH__
1036