summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier Bueno <javier.bueno@metempsy.com>2019-02-14 00:23:25 +0100
committerJavier Bueno Hedo <javier.bueno@metempsy.com>2019-06-03 13:45:50 +0000
commitb68735f9fad5879e606849e78e1a4ad3f77f1463 (patch)
tree1dc52c95b55021a951438e66e9f97bf20e08db46
parent87674842a6aeb2c94bf216a6c798b6db9814e00a (diff)
downloadgem5-b68735f9fad5879e606849e78e1a4ad3f77f1463.tar.xz
cpu: Added the Multiperspective Perceptron Predictor (8KB and 64KB)
Described by the following article: Jiménez, D. "Multiperspective perceptron predictor." Championship Branch Prediction (CBP-5) (2016). Change-Id: Iaa68ead7696e0b6ba05b4417d0322e8053e10d30 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/15495 Maintainer: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Ilias Vougioukas <ilias.vougioukas@arm.com> Tested-by: kokoro <noreply+kokoro@google.com>
-rw-r--r--src/cpu/pred/BranchPredictor.py82
-rw-r--r--src/cpu/pred/SConscript3
-rw-r--r--src/cpu/pred/multiperspective_perceptron.cc808
-rw-r--r--src/cpu/pred/multiperspective_perceptron.hh1027
-rw-r--r--src/cpu/pred/multiperspective_perceptron_64KB.cc93
-rw-r--r--src/cpu/pred/multiperspective_perceptron_64KB.hh53
-rw-r--r--src/cpu/pred/multiperspective_perceptron_8KB.cc72
-rw-r--r--src/cpu/pred/multiperspective_perceptron_8KB.hh53
8 files changed, 2191 insertions, 0 deletions
diff --git a/src/cpu/pred/BranchPredictor.py b/src/cpu/pred/BranchPredictor.py
index 9c59574ff..967489a16 100644
--- a/src/cpu/pred/BranchPredictor.py
+++ b/src/cpu/pred/BranchPredictor.py
@@ -475,3 +475,85 @@ class TAGE_SC_L_8KB(TAGE_SC_L):
tage = TAGE_SC_L_TAGE_8KB()
loop_predictor = TAGE_SC_L_8KB_LoopPredictor()
statistical_corrector = TAGE_SC_L_8KB_StatisticalCorrector()
+
+class MultiperspectivePerceptron(BranchPredictor):
+ type = 'MultiperspectivePerceptron'
+ cxx_class = 'MultiperspectivePerceptron'
+ cxx_header = 'cpu/pred/multiperspective_perceptron.hh'
+ abstract = True
+
+ num_filter_entries = Param.Int("Number of filter entries")
+ num_local_histories = Param.Int("Number of local history entries")
+ local_history_length = Param.Int(11,
+ "Length in bits of each history entry")
+
+ block_size = Param.Int(21,
+ "number of ghist bits in a 'block'; this is the width of an initial "
+ "hash of ghist")
+ pcshift = Param.Int(-10, "Shift for hashing PC")
+ threshold = Param.Int(1, "Threshold for deciding low/high confidence")
+ bias0 = Param.Int(-5,
+ "Bias perceptron output this much on all-bits-zero local history")
+ bias1 = Param.Int(5,
+ "Bias perceptron output this much on all-bits-one local history")
+ biasmostly0 = Param.Int(-1,
+ "Bias perceptron output this much on almost-all-bits-zero local "
+ "history")
+ biasmostly1 = Param.Int(1,
+ "Bias perceptron output this much on almost-all-bits-one local "
+ "history")
+ nbest = Param.Int(20,
+ "Use this many of the top performing tables on a low-confidence "
+ "branch")
+ tunebits = Param.Int(24, "Number of bits in misprediction counters")
+ hshift = Param.Int(-6,
+ "How much to shift initial feauture hash before XORing with PC bits")
+ imli_mask1 = Param.UInt64(
+ "Which tables should have their indices hashed with the first IMLI "
+ "counter")
+ imli_mask4 = Param.UInt64(
+ "Which tables should have their indices hashed with the fourth IMLI "
+ "counter")
+ recencypos_mask = Param.UInt64(
+ "Which tables should have their indices hashed with the recency "
+ "position")
+ fudge = Param.Float(0.245, "Fudge factor to multiply by perceptron output")
+ n_sign_bits = Param.Int(2, "Number of sign bits per magnitude")
+ pcbit = Param.Int(2, "Bit from the PC to use for hashing global history")
+ decay = Param.Int(0, "Whether and how often to decay a random weight")
+ record_mask = Param.Int(191,
+ "Which histories are updated with filtered branch outcomes")
+ hash_taken = Param.Bool(False,
+ "Hash the taken/not taken value with a PC bit")
+ tuneonly = Param.Bool(True,
+ "If true, only count mispredictions of low-confidence branches")
+ extra_rounds = Param.Int(1,
+ "Number of extra rounds of training a single weight on a "
+ "low-confidence prediction")
+ speed = Param.Int(9, "Adaptive theta learning speed")
+ initial_theta = Param.Int(10, "Initial theta")
+ budgetbits = Param.Int("Hardware budget in bits")
+ speculative_update = Param.Bool(False,
+ "Use speculative update for histories")
+
+class MultiperspectivePerceptron8KB(MultiperspectivePerceptron):
+ type = 'MultiperspectivePerceptron8KB'
+ cxx_class = 'MultiperspectivePerceptron8KB'
+ cxx_header = 'cpu/pred/multiperspective_perceptron_8KB.hh'
+ budgetbits = 8192 * 8 + 2048
+ num_local_histories = 48
+ num_filter_entries = 0
+ imli_mask1 = 0x6
+ imli_mask4 = 0x4400
+ recencypos_mask = 0x100000090
+
+class MultiperspectivePerceptron64KB(MultiperspectivePerceptron):
+ type = 'MultiperspectivePerceptron64KB'
+ cxx_class = 'MultiperspectivePerceptron64KB'
+ cxx_header = 'cpu/pred/multiperspective_perceptron_64KB.hh'
+ budgetbits = 65536 * 8 + 2048
+ num_local_histories = 510
+ num_filter_entries = 18025
+ imli_mask1 = 0xc1000
+ imli_mask4 = 0x80008000
+ recencypos_mask = 0x100000090
diff --git a/src/cpu/pred/SConscript b/src/cpu/pred/SConscript
index 736586197..27821a4aa 100644
--- a/src/cpu/pred/SConscript
+++ b/src/cpu/pred/SConscript
@@ -48,6 +48,9 @@ Source('tage_base.cc')
Source('tage.cc')
Source('loop_predictor.cc')
Source('ltage.cc')
+Source('multiperspective_perceptron.cc')
+Source('multiperspective_perceptron_8KB.cc')
+Source('multiperspective_perceptron_64KB.cc')
Source('statistical_corrector.cc')
Source('tage_sc_l.cc')
Source('tage_sc_l_8KB.cc')
diff --git a/src/cpu/pred/multiperspective_perceptron.cc b/src/cpu/pred/multiperspective_perceptron.cc
new file mode 100644
index 000000000..47bbb0212
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron.cc
@@ -0,0 +1,808 @@
+/*
+ * 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)
+ */
+
+#include "cpu/pred/multiperspective_perceptron.hh"
+
+#include "debug/Branch.hh"
+
+int
+MultiperspectivePerceptron::xlat[] =
+ {1,3,4,5,7,8,9,11,12,14,15,17,19,21,23,25,27,29,32,34,37,41,45,49,53,58,63,
+ 69,76,85,94,106,};
+int
+MultiperspectivePerceptron::xlat4[] =
+ {0,4,5,7,9,11,12,14,16,17,19,22,28,33,39,45,};
+
+MultiperspectivePerceptron::ThreadData::ThreadData(int num_filters,
+ 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)
+ : filterTable(num_filters), acyclic_histories(acyclic_bits.size()),
+ acyclic2_histories(acyclic_bits.size()),
+ blurrypath_histories(blurrypath_bits.size()),
+ ghist_words(ghist_length/block_size+1, 0),
+ path_history(path_length, 0), imli_counter(4,0),
+ localHistories(n_local_histories, local_history_length),
+ recency_stack(assoc), last_ghist_bit(false), occupancy(0)
+{
+ for (int i = 0; i < blurrypath_bits.size(); i+= 1) {
+ blurrypath_histories[i].resize(blurrypath_bits[i].size());
+ }
+
+ for (int i = 0; i < acyclic_bits.size(); i += 1) {
+ acyclic_histories[i].resize(acyclic_bits[i].size());
+ acyclic2_histories[i].resize(acyclic_bits[i].size());
+ }
+
+ int max_modhist_idx = -1;
+ for (auto &elem : modhist_indices) {
+ max_modhist_idx = (max_modhist_idx < elem) ? elem : max_modhist_idx;
+ }
+ if (max_modhist_idx >= 0) {
+ mod_histories.resize(max_modhist_idx + 1);
+ }
+ for (int i = 0; i < modhist_lengths.size(); i+= 1) {
+ mod_histories[modhist_indices[i]].resize(modhist_lengths[i]);
+ }
+
+ int max_modpath_idx = -1;
+ for (auto &elem : modpath_indices) {
+ max_modpath_idx = (max_modpath_idx < elem) ? elem : max_modpath_idx;
+ }
+ if (max_modpath_idx >= 0) {
+ modpath_histories.resize(max_modpath_idx + 1);
+ }
+ for (int i = 0; i < modpath_lengths.size(); i+= 1) {
+ modpath_histories[modpath_indices[i]].resize(modpath_lengths[i]);
+ }
+
+ for (int i = 0; i < table_sizes.size(); i += 1) {
+ mpreds.push_back(0);
+ tables.push_back(std::vector<short int>(table_sizes[i]));
+ sign_bits.push_back(std::vector<std::array<bool, 2>>(table_sizes[i]));
+ for (int j = 0; j < table_sizes[i]; j += 1) {
+ for (int k = 0; k < n_sign_bits; k += 1) {
+ sign_bits[i][j][k] = (i & 1) | (k & 1);
+ }
+ }
+ }
+}
+
+MultiperspectivePerceptron::MultiperspectivePerceptron(
+ const MultiperspectivePerceptronParams *p) : BPredUnit(p),
+ blockSize(p->block_size), pcshift(p->pcshift), threshold(p->threshold),
+ bias0(p->bias0), bias1(p->bias1), biasmostly0(p->biasmostly0),
+ biasmostly1(p->biasmostly1), nbest(p->nbest), tunebits(p->tunebits),
+ hshift(p->hshift), imli_mask1(p->imli_mask1), imli_mask4(p->imli_mask4),
+ recencypos_mask(p->recencypos_mask), fudge(p->fudge),
+ n_sign_bits(p->n_sign_bits), pcbit(p->pcbit), decay(p->decay),
+ record_mask(p->record_mask), hash_taken(p->hash_taken),
+ tuneonly(p->tuneonly), extra_rounds(p->extra_rounds), speed(p->speed),
+ budgetbits(p->budgetbits), speculative_update(p->speculative_update),
+ threadData(p->numThreads, nullptr), doing_local(false),
+ doing_recency(false), assoc(0), ghist_length(1), modghist_length(1),
+ path_length(1), randSeed(0xdeadbeef), thresholdCounter(0),
+ theta(p->initial_theta), imli_counter_bits(4), modhist_indices(),
+ modhist_lengths(), modpath_indices(), modpath_lengths()
+{
+ fatal_if(speculative_update, "Speculative update not implemented");
+}
+
+void
+MultiperspectivePerceptron::init()
+{
+ createSpecs();
+
+ for (auto &spec : specs) {
+ // initial assignation of values
+ table_sizes.push_back(spec->size);
+ }
+
+ // Update bit requirements and runtime values
+ for (auto &spec : specs) {
+ spec->setBitRequirements();
+ }
+ const MultiperspectivePerceptronParams *p =
+ static_cast<const MultiperspectivePerceptronParams *>(params());
+
+ computeBits(p->num_filter_entries, p->num_local_histories,
+ p->local_history_length);
+
+ for (int i = 0; i < threadData.size(); i += 1) {
+ threadData[i] = new ThreadData(p->num_filter_entries,
+ p->num_local_histories,
+ p->local_history_length, assoc,
+ blurrypath_bits, path_length,
+ ghist_length, blockSize, acyclic_bits,
+ modhist_indices, modhist_lengths,
+ modpath_indices, modpath_lengths,
+ table_sizes, n_sign_bits);
+ }
+}
+
+void
+MultiperspectivePerceptron::computeBits(int num_filter_entries,
+ int nlocal_histories, int local_history_length) {
+ int totalbits = 0;
+ for (auto &imli_bits : imli_counter_bits) {
+ totalbits += imli_bits;
+ }
+ totalbits += ghist_length;
+ totalbits += path_length * 16;
+ totalbits += (threshold >= 0) ? (tunebits * specs.size()) : 0;
+ for (auto &len : modhist_lengths) {
+ totalbits += len;
+ }
+ for (auto &len : modpath_lengths) {
+ totalbits += 16 * len;
+ }
+ totalbits += doing_local ? (nlocal_histories * local_history_length) : 0;
+ totalbits += doing_recency ? (assoc * 16) : 0;
+
+ for (auto &bv : blurrypath_bits) {
+ for (auto &bve : bv) {
+ totalbits += bve;
+ }
+ }
+ totalbits += num_filter_entries * 2;
+
+ for (auto &abi : acyclic_bits) {
+ for (auto &abj : abi) {
+ for (auto abk : abj) {
+ totalbits += abk;
+ }
+ }
+ }
+
+ int remaining = budgetbits - totalbits;
+
+ // count the tables that have already been assigned sizes
+ int num_sized = 0;
+ for (int i = 0; i < specs.size(); i +=1) {
+ if (table_sizes[i] != 0) {
+ int sz = table_sizes[i] * (specs[i]->width + (n_sign_bits - 1));
+ totalbits += sz;
+ remaining -= sz;
+ num_sized += 1;
+ }
+ }
+
+ // whatever is left, we divide among the rest of the tables
+ int table_size_bits = (remaining / (specs.size()-num_sized));
+ for (int i = 0; i < specs.size(); i += 1) {
+ // if a table doesn't have a size yet, give it one and count those bits
+ if (!table_sizes[i]) {
+ int my_table_size = table_size_bits /
+ (specs[i]->width + (n_sign_bits - 1)); // extra sign bits
+ table_sizes[i] = my_table_size;
+ totalbits += my_table_size * (specs[i]->width + (n_sign_bits - 1));
+ }
+ }
+
+ DPRINTF(Branch, "%d bits of metadata so far, %d left out of "
+ "%d total budget\n", totalbits, remaining, budgetbits);
+ DPRINTF(Branch, "table size is %d bits, %d entries for 5 bit, %d entries "
+ "for 6 bit\n", table_size_bits,
+ table_size_bits / (5 + (n_sign_bits - 1)),
+ table_size_bits / (6 + (n_sign_bits - 1)));
+ DPRINTF(Branch, "%d total bits (%0.2fKB)\n", totalbits,
+ totalbits / 8192.0);
+}
+
+void
+MultiperspectivePerceptron::findBest(ThreadID tid,
+ std::vector<int> &best_preds) const
+{
+ if (threshold < 0) {
+ return;
+ }
+ struct BestPair {
+ int index;
+ int mpreds;
+ bool operator<(BestPair const &bp) const
+ {
+ return mpreds < bp.mpreds;
+ }
+ };
+ std::vector<BestPair> pairs(best_preds.size());
+ for (int i = 0; i < best_preds.size(); i += 1) {
+ pairs[i].index = i;
+ pairs[i].mpreds = threadData[tid]->mpreds[i];
+ }
+ std::sort(pairs.begin(), pairs.end());
+ for (int i = 0; i < (std::min(nbest, (int) best_preds.size())); i += 1) {
+ best_preds[i] = pairs[i].index;
+ }
+}
+
+unsigned int
+MultiperspectivePerceptron::getIndex(ThreadID tid, const MPPBranchInfo &bi,
+ const HistorySpec &spec, int index) const
+{
+ unsigned int g = spec.getHash(tid, bi.getPC(), bi.getPC2(), index);
+ unsigned long long int h = g;
+ // shift the hash from the feature to xor with the hashed PC
+ if (hshift < 0) {
+ h <<= -hshift;
+ h ^= bi.getPC2();
+ } else {
+ h <<= hshift;
+ h ^= bi.getHPC();
+ }
+ // xor in the imli counter(s) and/or recency position based on the masks
+ if ((1ull<<index) & imli_mask1) {
+ h ^= threadData[tid]->imli_counter[0];
+ }
+ if ((1ull<<index) & imli_mask4) {
+ h ^= threadData[tid]->imli_counter[3];
+ }
+ if (doing_recency) {
+ if ((1ull<<index) & recencypos_mask) {
+ h ^= RECENCYPOS::hash(threadData[tid]->recency_stack, table_sizes,
+ bi.getPC2(), 31, index);
+ }
+ }
+ h %= table_sizes[index];
+ return h;
+}
+
+int
+MultiperspectivePerceptron::computeOutput(ThreadID tid, MPPBranchInfo &bi)
+{
+ // list of best predictors
+ std::vector<int> best_preds(specs.size(), -1);
+
+ // initialize sum
+ bi.yout = 0;
+
+ // bias the prediction by whether the local history is
+ // one of four distinctive patterns
+ int lhist = threadData[tid]->localHistories[bi.getPC()];
+ int history_len = threadData[tid]->localHistories.getLocalHistoryLength();
+ if (lhist == 0) {
+ bi.yout = bias0;
+ } else if (lhist == ((1<<history_len)-1)) {
+ bi.yout = bias1;
+ } else if (lhist == (1<<(history_len-1))) {
+ bi.yout = biasmostly0;
+ } else if (lhist == ((1<<(history_len-1))-1)) {
+ bi.yout = biasmostly1;
+ }
+ // find the best subset of features to use in case of a low-confidence
+ // branch
+ findBest(tid, best_preds);
+
+ // begin computation of the sum for low-confidence branch
+ int bestval = 0;
+
+ for (int i = 0; i < specs.size(); i += 1) {
+ HistorySpec const &spec = *specs[i];
+ // get the hash to index the table
+ unsigned int hashed_idx = getIndex(tid, bi, spec, i);
+ // add the weight; first get the weight's magnitude
+ int counter = threadData[tid]->tables[i][hashed_idx];
+ // get the sign
+ bool sign =
+ threadData[tid]->sign_bits[i][hashed_idx][bi.getHPC() % n_sign_bits];
+ // apply the transfer function and multiply by a coefficient
+ int weight = spec.coeff * ((spec.width == 5) ?
+ xlat4[counter] : xlat[counter]);
+ // apply the sign
+ int val = sign ? -weight : weight;
+ // add the value
+ bi.yout += val;
+ // if this is one of those good features, add the value to bestval
+ if (threshold >= 0) {
+ for (int j = 0;
+ j < std::min(nbest, (int) best_preds.size());
+ j += 1)
+ {
+ if (best_preds[j] == i) {
+ bestval += val;
+ break;
+ }
+ }
+ }
+ }
+ // apply a fudge factor to affect when training is triggered
+ bi.yout *= fudge;
+ return bestval;
+}
+
+void
+MultiperspectivePerceptron::satIncDec(bool taken, bool &sign, int &counter,
+ int max_weight) const
+{
+ if (taken) {
+ // increment sign/magnitude
+ if (sign) {
+ // go toward 0 away from negative max weight
+ if (counter == 0) {
+ sign = false; // moved to positive 0
+ } else {
+ counter -= 1;
+ }
+ } else {
+ // go toward max weight away from 0
+ if (counter < max_weight) {
+ counter += 1;
+ }
+ }
+ } else {
+ // decrement sign/magnitude
+ if (sign) {
+ // go toward negative max weight down from 0
+ if (counter < max_weight) {
+ counter += 1;
+ }
+ } else {
+ // go toward 0 away from max weight
+ if (counter == 0) {
+ sign = true; // negative 0
+ } else {
+ counter -= 1;
+ }
+ }
+ }
+}
+
+void
+MultiperspectivePerceptron::train(ThreadID tid, MPPBranchInfo &bi, bool taken)
+{
+ std::vector<std::vector<short int>> &tables = threadData[tid]->tables;
+ std::vector<std::vector<std::array<bool, 2>>> &sign_bits =
+ threadData[tid]->sign_bits;
+ std::vector<int> &mpreds = threadData[tid]->mpreds;
+ // was the prediction correct?
+ bool correct = (bi.yout >= 1) == taken;
+ // what is the magnitude of yout?
+ int abs_yout = abs(bi.yout);
+ // keep track of mispredictions per table
+ if (threshold >= 0) if (!tuneonly || (abs_yout <= threshold)) {
+ bool halve = false;
+
+ // for each table, figure out if there was a misprediction
+ for (int i = 0; i < specs.size(); i += 1) {
+ HistorySpec const &spec = *specs[i];
+ // get the hash to index the table
+ unsigned int hashed_idx = getIndex(tid, bi, spec, i);
+ bool sign = sign_bits[i][hashed_idx][bi.getHPC() % n_sign_bits];
+ int counter = tables[i][hashed_idx];
+ int weight = spec.coeff * ((spec.width == 5) ?
+ xlat4[counter] : xlat[counter]);
+ if (sign) weight = -weight;
+ bool pred = weight >= 1;
+ if (pred != taken) {
+ mpreds[i] += 1;
+ if (mpreds[i] == (1 << tunebits) - 1) {
+ halve = true;
+ }
+ }
+ }
+ // if we reach the maximum counter value, halve all the counters
+ if (halve) {
+ for (int i = 0; i < specs.size(); i += 1) {
+ mpreds[i] /= 2;
+ }
+ }
+ }
+ // if the branch was predicted incorrectly or the correct
+ // prediction was weak, update the weights
+ bool do_train = !correct || (abs_yout <= theta);
+ if (!do_train) return;
+
+ // adaptive theta training, adapted from O-GEHL
+ if (!correct) {
+ thresholdCounter += 1;
+ if (thresholdCounter >= speed) {
+ theta += 1;
+ thresholdCounter = 0;
+ }
+ }
+ if (correct && abs_yout < theta) {
+ thresholdCounter -= 1;
+ if (thresholdCounter <= -speed) {
+ theta -= 1;
+ thresholdCounter = 0;
+ }
+ }
+
+ // train the weights, computing what the value of yout
+ // would have been if these updates had been applied before
+ int newyout = 0;
+ for (int i = 0; i < specs.size(); i += 1) {
+ HistorySpec const &spec = *specs[i];
+ // get the magnitude
+ unsigned int hashed_idx = getIndex(tid, bi, spec, i);
+ int counter = tables[i][hashed_idx];
+ // get the sign
+ bool sign = sign_bits[i][hashed_idx][bi.getHPC() % n_sign_bits];
+ // increment/decrement if taken/not taken
+ satIncDec(taken, sign, counter, (1 << (spec.width - 1)) - 1);
+ // update the magnitude and sign
+ tables[i][hashed_idx] = counter;
+ sign_bits[i][hashed_idx][bi.getHPC() % n_sign_bits] = sign;
+ int weight = ((spec.width == 5) ? xlat4[counter] : xlat[counter]);
+ // update the new version of yout
+ if (sign) {
+ newyout -= weight;
+ } else {
+ newyout += weight;
+ }
+ }
+
+ // if the prediction still would have been incorrect even
+ // with the updated weights, update some more weights to
+ // try to fix the problem
+ if ((newyout >= 1) != taken) {
+ if (extra_rounds != -1) {
+ int round_counter = 0;
+ bool found;
+ do {
+ // udpate a random weight
+ int besti = -1;
+ int nrand = rand_r(&randSeed) % specs.size();
+ int pout;
+ found = false;
+ for (int j = 0; j < specs.size(); j += 1) {
+ int i = (nrand + j) % specs.size();
+ HistorySpec const &spec = *specs[i];
+ unsigned int hashed_idx = getIndex(tid, bi, spec, i);
+ int counter = tables[i][hashed_idx];
+ bool sign =
+ sign_bits[i][hashed_idx][bi.getHPC() % n_sign_bits];
+ int weight = ((spec.width == 5) ?
+ xlat4[counter] : xlat[counter]);
+ int signed_weight = sign ? -weight : weight;
+ pout = newyout - signed_weight;
+ if ((pout >= 1) == taken) {
+ // we have found a weight that if we blow
+ // it away will help!
+ besti = i;
+ break;
+ }
+ }
+ if (besti != -1) {
+ int i = besti;
+ HistorySpec const &spec = *specs[i];
+ unsigned int hashed_idx = getIndex(tid, bi, spec, i);
+ int counter = tables[i][hashed_idx];
+ bool sign =
+ sign_bits[i][hashed_idx][bi.getHPC() % n_sign_bits];
+ if (counter > 1) {
+ counter--;
+ tables[i][hashed_idx] = counter;
+ }
+ int weight = ((spec.width == 5) ?
+ xlat4[counter] : xlat[counter]);
+ int signed_weight = sign ? -weight : weight;
+ int out = pout + signed_weight;
+ round_counter += 1;
+ if ((out >= 1) != taken) {
+ found = true;
+ }
+ }
+ } while (found && round_counter < extra_rounds);
+ }
+ }
+}
+
+void
+MultiperspectivePerceptron::uncondBranch(ThreadID tid, Addr pc,
+ void * &bp_history)
+{
+ MPPBranchInfo *bi = new MPPBranchInfo(pc, pcshift, false);
+ std::vector<unsigned int> &ghist_words = threadData[tid]->ghist_words;
+
+ bp_history = (void *)bi;
+ unsigned short int pc2 = pc >> 2;
+ bool ab = !(pc & (1<<pcbit));
+ for (int i = 0; i < ghist_length / blockSize + 1; i += 1) {
+ bool ab_new = (ghist_words[i] >> (blockSize - 1)) & 1;
+ ghist_words[i] <<= 1;
+ ghist_words[i] |= ab;
+ ghist_words[i] &= (1 << blockSize) - 1;
+ ab = ab_new;
+ }
+ memmove(&threadData[tid]->path_history[1],
+ &threadData[tid]->path_history[0],
+ sizeof(unsigned short int) * (path_length - 1));
+ threadData[tid]->path_history[0] = pc2;
+}
+
+bool
+MultiperspectivePerceptron::lookup(ThreadID tid, Addr instPC,
+ void * &bp_history)
+{
+ MPPBranchInfo *bi = new MPPBranchInfo(instPC, pcshift, true);
+ bp_history = (void *)bi;
+
+ bool use_static = false;
+
+ if (!threadData[tid]->filterTable.empty()) {
+ unsigned int findex =
+ bi->getHashFilter(threadData[tid]->last_ghist_bit) %
+ threadData[tid]->filterTable.size();
+ FilterEntry &f = threadData[tid]->filterTable[findex];
+ if (f.alwaysNotTakenSoFar()) {
+ bi->filtered = true;
+ bi->prediction = false;
+ return false;
+ } else if (f.alwaysTakenSoFar()) {
+ bi->filtered = true;
+ bi->prediction = true;
+ return true;
+ }
+ if (f.neverSeen()) {
+ use_static = true;
+ }
+ }
+
+ int bestval = computeOutput(tid, *bi);
+ if (use_static) {
+ bi->prediction = false;
+ } else {
+ if (abs(bi->yout) <= threshold) {
+ bi->prediction = (bestval >= 1);
+ } else {
+ bi->prediction = (bi->yout >= 1);
+ }
+ }
+
+ return bi->prediction;
+}
+
+void
+MultiperspectivePerceptron::update(ThreadID tid, Addr instPC, bool taken,
+ void *bp_history, bool squashed,
+ const StaticInstPtr & inst,
+ Addr corrTarget)
+{
+ assert(bp_history);
+ MPPBranchInfo *bi = static_cast<MPPBranchInfo*>(bp_history);
+ assert(corrTarget != MaxAddr);
+ if (squashed) {
+ //delete bi;
+ return;
+ }
+
+ if (bi->isUnconditional()) {
+ delete bi;
+ return;
+ }
+
+ bool do_train = true;
+
+ if (!threadData[tid]->filterTable.empty()) {
+ int findex = bi->getHashFilter(threadData[tid]->last_ghist_bit) %
+ threadData[tid]->filterTable.size();
+ FilterEntry &f = threadData[tid]->filterTable[findex];
+
+ // compute this first, so we don't not train on the
+ // first time a branch is seen.
+ bool transition = false;
+ if (f.alwaysNotTakenSoFar() || f.alwaysTakenSoFar()) {
+ do_train = false;
+ }
+ if (taken) {
+ if (f.alwaysNotTakenSoFar()) {
+ transition = true;
+ }
+ f.seenTaken = true;
+ } else {
+ if (f.alwaysTakenSoFar()) {
+ transition = true;
+ }
+ f.seenUntaken = true;
+ }
+ // is this the first time time the branch has gone both ways?
+ if (transition) {
+ threadData[tid]->occupancy += 1;
+ }
+ // for every new dynamic branch, when there ar
+ // more than 'decay' number of branches in the
+ // filter, blow a random filter entry away
+ if (decay && transition &&
+ ((threadData[tid]->occupancy > decay) || (decay == 1))) {
+ int rnd = rand_r(&randSeed) % threadData[tid]->filterTable.size();
+ FilterEntry &frand = threadData[tid]->filterTable[rnd];
+ if (frand.seenTaken && frand.seenUntaken) {
+ threadData[tid]->occupancy -= 1;
+ }
+ frand.seenTaken = false;
+ frand.seenUntaken = false;
+ }
+ }
+
+ if (do_train) {
+ train(tid, *bi, taken);
+ }
+
+#define RECORD_FILTERED_IMLI 1
+#define RECORD_FILTERED_GHIST 2
+#define RECORD_FILTERED_PATH 4
+#define RECORD_FILTERED_ACYCLIC 8
+#define RECORD_FILTERED_MOD 16
+#define RECORD_FILTERED_BLURRY 32
+// should never record a filtered local branch - duh!
+#define RECORD_FILTERED_LOCAL 64
+#define RECORD_FILTERED_RECENCY 128
+
+ // four different styles of IMLI
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_IMLI)) {
+ unsigned int target = corrTarget;
+ if (target < bi->getPC()) {
+ if (taken) {
+ threadData[tid]->imli_counter[0] += 1;
+ } else {
+ threadData[tid]->imli_counter[0] = 0;
+ }
+ if (!taken) {
+ threadData[tid]->imli_counter[1] += 1;
+ } else {
+ threadData[tid]->imli_counter[1] = 0;
+ }
+ } else {
+ if (taken) {
+ threadData[tid]->imli_counter[2] += 1;
+ } else {
+ threadData[tid]->imli_counter[2] = 0;
+ }
+ if (!taken) {
+ threadData[tid]->imli_counter[3] += 1;
+ } else {
+ threadData[tid]->imli_counter[3] = 0;
+ }
+ }
+ }
+
+ bool hashed_taken = hash_taken ? (taken ^ !!(bi->getPC() & (1<<pcbit)))
+ : taken;
+ // record into ghist
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_GHIST)) {
+ bool ab = hashed_taken;
+ assert(threadData[tid]->ghist_words.size() > 0);
+ for (int i = 0; i < ghist_length / blockSize + 1; i += 1) {
+ unsigned int a = threadData[tid]->ghist_words[i];
+ bool ab_new = (a >> (blockSize - 1)) & 1;
+ a <<= 1;
+ a |= ab;
+ ab = ab_new;
+ a &= (1 << blockSize) - 1;
+ threadData[tid]->ghist_words[i] = a;
+ }
+ }
+
+ // record into path history
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_PATH)) {
+ assert(threadData[tid]->path_history.size() > 0);
+ memmove(&threadData[tid]->path_history[1],
+ &threadData[tid]->path_history[0],
+ sizeof(unsigned short int) * (path_length - 1));
+ threadData[tid]->path_history[0] = bi->getPC2();
+ }
+
+ // record into acyclic history
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_ACYCLIC)) {
+ threadData[tid]->updateAcyclic(hashed_taken, bi->getHPC());
+ }
+
+ // record into modulo path history
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_MOD)) {
+ for (int ii = 0; ii < modpath_indices.size(); ii += 1) {
+ int i = modpath_indices[ii];
+ if (bi->getHPC() % (i + 2) == 0) {
+ memmove(&threadData[tid]->modpath_histories[i][1],
+ &threadData[tid]->modpath_histories[i][0],
+ sizeof(unsigned short int) * (modpath_lengths[ii]-1));
+ threadData[tid]->modpath_histories[i][0] = bi->getPC2();
+ }
+ }
+ }
+
+ // update blurry history
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_BLURRY)) {
+ std::vector<std::vector<unsigned int>> &blurrypath_histories =
+ threadData[tid]->blurrypath_histories;
+
+ for (int i = 0; i < blurrypath_histories.size(); i += 1)
+ {
+ if (blurrypath_histories[i].size() > 0) {
+ unsigned int z = bi->getPC() >> i;
+ if (blurrypath_histories[i][0] != z) {
+ memmove(&blurrypath_histories[i][1],
+ &blurrypath_histories[i][0],
+ sizeof(unsigned int) *
+ (blurrypath_histories[i].size() - 1));
+ blurrypath_histories[i][0] = z;
+ }
+ }
+ }
+ }
+
+ // record into modulo pattern history
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_MOD)) {
+ for (int ii = 0; ii < modhist_indices.size(); ii += 1) {
+ int i = modhist_indices[ii];
+ if (bi->getHPC() % (i + 2) == 0) {
+ for (int j = modhist_lengths[ii] - 1; j > 0; j -= 1) {
+ threadData[tid]->mod_histories[i][j] =
+ threadData[tid]->mod_histories[i][j-1];
+ }
+ threadData[tid]->mod_histories[i][0] = hashed_taken;
+ }
+ }
+ }
+
+ // insert this PC into the recency stack
+ if (doing_recency) {
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_RECENCY)) {
+ threadData[tid]->insertRecency(bi->getPC2(), assoc);
+ }
+ }
+
+ // record into a local history
+ if (!bi->filtered || (record_mask & RECORD_FILTERED_LOCAL)) {
+ threadData[tid]->localHistories.update(bi->getPC(), hashed_taken);
+ }
+
+ // update last ghist bit, used to index filter
+ threadData[tid]->last_ghist_bit = taken;
+
+ delete bi;
+}
+
+void
+MultiperspectivePerceptron::btbUpdate(ThreadID tid, Addr branch_pc,
+ void* &bp_history)
+{
+}
+
+void
+MultiperspectivePerceptron::squash(ThreadID tid, void *bp_history)
+{
+ assert(bp_history);
+ MPPBranchInfo *bi = static_cast<MPPBranchInfo*>(bp_history);
+ delete bi;
+}
diff --git a/src/cpu/pred/multiperspective_perceptron.hh b/src/cpu/pred/multiperspective_perceptron.hh
new file mode 100644
index 000000000..e81bd8eec
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron.hh
@@ -0,0 +1,1027 @@
+/*
+ * 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;
+ unsigned int randSeed;
+ int thresholdCounter;
+ int theta;
+ 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
+ */
+ void computeBits(int num_filter_entries, int nlocal_histories,
+ int local_history_length);
+
+ /**
+ * 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);
+
+ 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__
diff --git a/src/cpu/pred/multiperspective_perceptron_64KB.cc b/src/cpu/pred/multiperspective_perceptron_64KB.cc
new file mode 100644
index 000000000..a5d724183
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_64KB.cc
@@ -0,0 +1,93 @@
+/*
+ * 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)
+ * - 64KB version
+ */
+
+#include "cpu/pred/multiperspective_perceptron_64KB.hh"
+
+MultiperspectivePerceptron64KB::MultiperspectivePerceptron64KB(
+ const MultiperspectivePerceptron64KBParams *p)
+ : MultiperspectivePerceptron(p)
+{
+}
+
+void
+MultiperspectivePerceptron64KB::createSpecs() {
+ addSpec(new ACYCLIC(10, -1, -1, 1.0, 0, 6, *this));
+ addSpec(new BLURRYPATH(10, 7, -1, 1.0, 0, 6, *this));
+ addSpec(new GHIST(0, 19, 1.3125, 0, 6, *this));
+ addSpec(new GHIST(0, 65, 0.85, 0, 6, *this));
+ addSpec(new GHIST(111, 222, 1.0, 0, 6, *this));
+ addSpec(new GHIST(115, 206, 1.0, 0, 6, *this));
+ addSpec(new GHIST(190, 336, 1.0, 0, 6, *this));
+ addSpec(new GHIST(21, 64, 1.0, 0, 6, *this));
+ addSpec(new GHIST(48, 119, 1.0, 0, 6, *this));
+ addSpec(new GHIST(67, 203, 0.75, 0, 6, *this));
+ addSpec(new GHIST(75, 150, 1.0, 0, 6, *this));
+ addSpec(new GHISTMODPATH(1, 5, 4, 1.45, 1913, 6, *this));
+ addSpec(new GHISTMODPATH(3, 13, 1, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(105, 4, 0, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(11, 2, -1, 1.25, 0, 6, *this));
+ addSpec(new GHISTPATH(15, 4, -1, 1.125, 0, 6, *this));
+ addSpec(new GHISTPATH(23, 4, -1, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(31, 1, -1, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(32, 2, -1, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(36, 4, -1, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(51, 1, 0, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(7, 1, -1, 1.5, 0, 6, *this));
+ addSpec(new GHISTPATH(72, 1, -1, 1.0, 0, 6, *this));
+ addSpec(new GHISTPATH(86, 4, 0, 1.0, 0, 6, *this));
+ addSpec(new IMLI(1, 1.8125, 0, 6, *this));
+ addSpec(new IMLI(4, 1.78125, 1536, 6, *this));
+ addSpec(new LOCAL(-1, 1.0, 1024, 6, *this));
+ addSpec(new LOCAL(-1, 2.0, 3467, 6, *this));
+ addSpec(new MODHIST(1, 16, 0.9375, 0, 6, *this));
+ addSpec(new MODPATH(3, 20, 1, 1.0, 0, 6, *this));
+ addSpec(new PATH(13, 2, -1, 1.4375, 0, 6, *this));
+ addSpec(new PATH(27, 5, -1, 1.0, 0, 6, *this));
+ addSpec(new RECENCY(10, 3, -1, 0.55, 1024, 6, *this));
+ addSpec(new RECENCY(14, 4, -1, 1.3125, 0, 6, *this));
+ addSpec(new RECENCYPOS(31, 1.5, 0, 6, *this));
+ addSpec(new SGHISTPATH(1, 2, 5, 1.25, 768, 6, *this));
+ addSpec(new SGHISTPATH(1, 5, 2, 1.3125, 972, 6, *this));
+}
+
+ MultiperspectivePerceptron64KB*
+MultiperspectivePerceptron64KBParams::create()
+{
+ return new MultiperspectivePerceptron64KB(this);
+}
diff --git a/src/cpu/pred/multiperspective_perceptron_64KB.hh b/src/cpu/pred/multiperspective_perceptron_64KB.hh
new file mode 100644
index 000000000..a87020b6d
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_64KB.hh
@@ -0,0 +1,53 @@
+/*
+ * 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)
+ * - 64KB version
+ */
+
+#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_64KB_HH__
+#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_64KB_HH__
+
+#include "cpu/pred/multiperspective_perceptron.hh"
+#include "params/MultiperspectivePerceptron64KB.hh"
+
+class MultiperspectivePerceptron64KB : public MultiperspectivePerceptron {
+ void createSpecs() override;
+ public:
+ MultiperspectivePerceptron64KB(
+ const MultiperspectivePerceptron64KBParams *p);
+};
+
+#endif // __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_64KB_HH__
diff --git a/src/cpu/pred/multiperspective_perceptron_8KB.cc b/src/cpu/pred/multiperspective_perceptron_8KB.cc
new file mode 100644
index 000000000..832e17237
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_8KB.cc
@@ -0,0 +1,72 @@
+/*
+ * 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)
+ * - 8KB version
+ */
+
+#include "cpu/pred/multiperspective_perceptron_8KB.hh"
+
+MultiperspectivePerceptron8KB::MultiperspectivePerceptron8KB(
+ const MultiperspectivePerceptron8KBParams *p)
+ : MultiperspectivePerceptron(p)
+{
+}
+
+void
+MultiperspectivePerceptron8KB::createSpecs() {
+ addSpec(new BIAS(2.40625, 0, 6, *this));
+ addSpec(new GHIST(0, 19, 1.4375, 0, 6, *this));
+ addSpec(new GHIST(0, 65, 1.0, 0, 6, *this));
+ addSpec(new GHIST(21, 64, 1.0, 0, 6, *this));
+ addSpec(new GHIST(75, 150, 1.0625, 0, 6, *this));
+ addSpec(new GHISTMODPATH(0, 7, 3, 1.625, 0, 6, *this));
+ addSpec(new GHISTPATH(11, 2, -1, 1.25, 0, 6, *this));
+ addSpec(new GHISTPATH(15, 4, -1, 1.125, 0, 6, *this));
+ addSpec(new GHISTPATH(31, 1, -1, 1.40625, 0, 6, *this));
+ addSpec(new GHISTPATH(7, 1, -1, 1.5, 600, 6, *this));
+ addSpec(new IMLI(4, 1.28125, 375, 6, *this));
+ addSpec(new LOCAL(-1, 1.5625, 512, 6, *this));
+ addSpec(new RECENCY(14, 4, -1, 1.25, 0, 6, *this));
+ addSpec(new RECENCYPOS(31, 1.875, 0, 6, *this));
+ addSpec(new SGHISTPATH(0, 4, 3, 1.65625, 0, 6, *this));
+ addSpec(new SGHISTPATH(1, 2, 5, 2.53125, 0, 5, *this));
+}
+
+ MultiperspectivePerceptron8KB*
+MultiperspectivePerceptron8KBParams::create()
+{
+ return new MultiperspectivePerceptron8KB(this);
+}
diff --git a/src/cpu/pred/multiperspective_perceptron_8KB.hh b/src/cpu/pred/multiperspective_perceptron_8KB.hh
new file mode 100644
index 000000000..032ecdf03
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_8KB.hh
@@ -0,0 +1,53 @@
+/*
+ * 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)
+ * - 8KB version
+ */
+
+#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_8KB_HH__
+#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_8KB_HH__
+
+#include "cpu/pred/multiperspective_perceptron.hh"
+#include "params/MultiperspectivePerceptron8KB.hh"
+
+class MultiperspectivePerceptron8KB : public MultiperspectivePerceptron {
+ void createSpecs() override;
+ public:
+ MultiperspectivePerceptron8KB(
+ const MultiperspectivePerceptron8KBParams *p);
+};
+
+#endif // __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_8KB_HH__