Javier Bueno Hedo has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/15775
Change subject: cpu: Move the Loop Predictor from LTAGE to an external class
......................................................................
cpu: Move the Loop Predictor from LTAGE to an external class
This code could be reused by other predictors requiring a loop predictor.
Change-Id: I60ad079a2c49b00a1f84d5cfd3611631883a4b57
---
M src/cpu/pred/SConscript
A src/cpu/pred/loop_predictor.cc
A src/cpu/pred/loop_predictor.hh
M src/cpu/pred/ltage.cc
M src/cpu/pred/ltage.hh
M src/cpu/pred/tage_sc_l.cc
6 files changed, 648 insertions(+), 419 deletions(-)
diff --git a/src/cpu/pred/SConscript b/src/cpu/pred/SConscript
index 0028445..168a99b 100644
--- a/src/cpu/pred/SConscript
+++ b/src/cpu/pred/SConscript
@@ -45,6 +45,7 @@
Source ('bi_mode.cc')
Source('tage_base.cc')
Source('tage.cc')
+Source('loop_predictor.cc')
Source('ltage.cc')
Source('tage_sc_l.cc')
Source('tage_sc_l_8KB.cc')
diff --git a/src/cpu/pred/loop_predictor.cc b/src/cpu/pred/loop_predictor.cc
new file mode 100644
index 0000000..fd97943
--- /dev/null
+++ b/src/cpu/pred/loop_predictor.cc
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2014 The University of Wisconsin
+ *
+ * Copyright (c) 2006 INRIA (Institut National de Recherche en
+ * Informatique et en Automatique / French National Research Institute
+ * for Computer Science and Applied Mathematics)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * 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;
+ * neither the name of the copyright holders 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
+ * OWNER 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.
+ *
+ * Authors: Vignyan Reddy, Dibakar Gope and Arthur Perais,
+ * from André Seznec's code.
+ */
+
+#include "cpu/pred/loop_predictor.hh"
+
+#include "base/trace.hh"
+
+LoopPredictor::LoopPredictor(unsigned log_size_loop_pred,
+ unsigned loop_table_age_bits, unsigned loop_table_confidence_bits,
+ unsigned loop_table_tag_bits, unsigned loop_table_iter_bits,
+ unsigned log_loop_table_assoc, unsigned with_loop_bits,
+ bool use_direction_bit, bool use_speculation, bool use_hashing,
+ bool restrict_allocation, unsigned initial_loop_iter,
+ unsigned initial_loop_age, bool optional_age_reset)
+ : logSizeLoopPred(log_size_loop_pred),
+ loopTableAgeBits(loop_table_age_bits),
+ loopTableConfidenceBits(loop_table_confidence_bits),
+ loopTableTagBits(loop_table_tag_bits),
+ loopTableIterBits(loop_table_iter_bits),
+ logLoopTableAssoc(log_loop_table_assoc),
+ confidenceThreshold((1 << loopTableConfidenceBits) - 1),
+ loopTagMask((1 << loopTableTagBits) - 1),
+ loopNumIterMask((1 << loopTableIterBits) - 1),
+ loopSetMask((1 << (logSizeLoopPred - logLoopTableAssoc)) - 1),
+ loopUseCounter(-1),
+ withLoopBits(with_loop_bits),
+ useDirectionBit(use_direction_bit),
+ useSpeculation(use_speculation),
+ useHashing(use_hashing),
+ restrictAllocation(restrict_allocation),
+ initialLoopIter(initial_loop_iter),
+ initialLoopAge(initial_loop_age),
+ optionalAgeReset(optional_age_reset)
+{
+ assert(initialLoopAge <= ((1 << loopTableAgeBits) - 1));
+}
+
+void
+LoopPredictor::init()
+{
+ // we use uint16_t type for these vales, so they cannot be more than
+ // 16 bits
+ assert(loopTableTagBits <= 16);
+ assert(loopTableIterBits <= 16);
+
+ assert(logSizeLoopPred >= logLoopTableAssoc);
+
+ ltable = new LoopEntry[ULL(1) << logSizeLoopPred];
+}
+
+int
+LoopPredictor::lindex(Addr pc_in, unsigned instShiftAmt) const
+{
+ // The loop table is implemented as a linear table
+ // If associativity is N (N being 1 << logLoopTableAssoc),
+ // the first N entries are for set 0, the next N entries are for set 1,
+ // and so on.
+ // Thus, this function calculates the set and then it gets left shifted
+ // by logLoopTableAssoc in order to return the index of the first of
the
+ // N entries of the set
+ Addr pc = pc_in >> instShiftAmt;
+ if (useHashing) {
+ // copied from TAGE-SC-L
+ // (http://www.jilp.org/cbp2016/code/AndreSeznecLimited.tar.gz)
+ pc ^= pc_in;
+ }
+ return ((pc & loopSetMask) << logLoopTableAssoc);
+}
+
+int
+LoopPredictor::finallindex(int index, int lowPcBits, int way) const
+{
+ // copied from TAGE-SC-L
+ // (http://www.jilp.org/cbp2016/code/AndreSeznecLimited.tar.gz)
+ return (useHashing ? (index ^ ((lowPcBits >> way) <<
logLoopTableAssoc)) :
+ (index))
+ + way;
+}
+
+//loop prediction: only used if high confidence
+bool
+LoopPredictor::getLoop(Addr pc, BranchInfo* bi, bool speculative,
+ unsigned instShiftAmt) const
+{
+ bi->loopHit = -1;
+ bi->loopPredValid = false;
+ bi->loopIndex = lindex(pc, instShiftAmt);
+
+ if (useHashing) {
+ unsigned pcShift = logSizeLoopPred - logLoopTableAssoc;
+ bi->loopIndexB = (pc >> pcShift) & loopSetMask;
+ bi->loopTag = (pc >> pcShift) ^ (pc >> (pcShift +
loopTableTagBits));
+ bi->loopTag &= loopTagMask;
+ } else {
+ unsigned pcShift = instShiftAmt + logSizeLoopPred -
logLoopTableAssoc;
+ bi->loopTag = (pc >> pcShift) & loopTagMask;
+ // bi->loopIndexB is not used without hash
+ }
+
+ for (int i = 0; i < (1 << logLoopTableAssoc); i++) {
+ int idx = finallindex(bi->loopIndex, bi->loopIndexB, i);
+ if (ltable[idx].tag == bi->loopTag) {
+ bi->loopHit = i;
+ bi->loopPredValid = calcConf(idx);
+
+ uint16_t iter = speculative ? ltable[idx].currentIterSpec
+ : ltable[idx].currentIter;
+
+ if ((iter + 1) == ltable[idx].numIter) {
+ return useDirectionBit ? !(ltable[idx].dir) : false;
+ } else {
+ return useDirectionBit ? (ltable[idx].dir) : true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+LoopPredictor::calcConf(int index) const
+{
+ return ltable[index].confidence == confidenceThreshold;
+}
+
+void
+LoopPredictor::specLoopUpdate(bool taken, BranchInfo* bi)
+{
+ if (bi->loopHit>=0) {
+ int index = finallindex(bi->loopIndex, bi->loopIndexB,
bi->loopHit);
+ if (taken != ltable[index].dir) {
+ ltable[index].currentIterSpec = 0;
+ } else {
+ ltable[index].currentIterSpec =
+ (ltable[index].currentIterSpec + 1) & loopNumIterMask;
+ }
+ }
+}
+
+bool
+LoopPredictor::optionalAgeInc() const
+{
+ return false;
+}
+
+void
+LoopPredictor::loopUpdate(Addr pc, bool taken, BranchInfo* bi, bool
tage_pred,
+ int random0, int random1)
+{
+ int idx = finallindex(bi->loopIndex, bi->loopIndexB, bi->loopHit);
+ if (bi->loopHit >= 0) {
+ //already a hit
+ if (bi->loopPredValid) {
+ if (taken != bi->loopPred) {
+ // free the entry
+ ltable[idx].numIter = 0;
+ ltable[idx].age = 0;
+ ltable[idx].confidence = 0;
+ ltable[idx].currentIter = 0;
+ return;
+ } else if (bi->loopPred != tage_pred || optionalAgeInc()) {
+ unsignedCtrUpdate(ltable[idx].age, true, loopTableAgeBits);
+ }
+ }
+
+ ltable[idx].currentIter =
+ (ltable[idx].currentIter + 1) & loopNumIterMask;
+ if (ltable[idx].currentIter > ltable[idx].numIter) {
+ ltable[idx].confidence = 0;
+ if (ltable[idx].numIter != 0) {
+ // free the entry
+ ltable[idx].numIter = 0;
+ if (optionalAgeReset) {
+ ltable[idx].age = 0;
+ }
+ }
+ }
+
+ if (taken != (useDirectionBit ? ltable[idx].dir : true)) {
+ if (ltable[idx].currentIter == ltable[idx].numIter) {
+ unsignedCtrUpdate(ltable[idx].confidence, true,
+ loopTableConfidenceBits);
+ //just do not predict when the loop count is 1 or 2
+ if (ltable[idx].numIter < 3) {
+ // free the entry
+ ltable[idx].dir = taken; // ignored if no
useDirectionBit
+ ltable[idx].numIter = 0;
+ ltable[idx].age = 0;
+ ltable[idx].confidence = 0;
+ }
+ } else {
+ //DPRINTF(LTage, "Loop End predicted incorrectly:%lx\n",
pc);
+ if (ltable[idx].numIter == 0) {
+ // first complete nest;
+ ltable[idx].confidence = 0;
+ ltable[idx].numIter = ltable[idx].currentIter;
+ } else {
+ //not the same number of iterations as last time: free
the
+ //entry
+ ltable[idx].numIter = 0;
+ if (optionalAgeReset) {
+ ltable[idx].age = 0;
+ }
+ ltable[idx].confidence = 0;
+ }
+ }
+ ltable[idx].currentIter = 0;
+ }
+
+ } else if (useDirectionBit ? (bi->predTaken != taken) : taken) {
+ if ((random1 & 3) == 0 || !restrictAllocation) {
+ //try to allocate an entry on taken branch
+ int nrand = random0;
+ for (int i = 0; i < (1 << logLoopTableAssoc); i++) {
+ int loop_hit = (nrand + i) & ((1 << logLoopTableAssoc) -
1);
+ idx = finallindex(bi->loopIndex, bi->loopIndexB, loop_hit);
+ if (ltable[idx].age == 0) {
+ ltable[idx].dir = !taken; // ignored if no
useDirectionBit
+ ltable[idx].tag = bi->loopTag;
+ ltable[idx].numIter = 0;
+ ltable[idx].age = initialLoopAge;
+ ltable[idx].confidence = 0;
+ ltable[idx].currentIter = initialLoopIter;
+ break;
+
+ } else {
+ ltable[idx].age--;
+ }
+ if (restrictAllocation) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool
+LoopPredictor::loopPredict(ThreadID tid, Addr branch_pc, bool cond_branch,
+ BranchInfo* bi, bool prev_pred_taken, unsigned
instShiftAmt)
+{
+ bool pred_taken = prev_pred_taken;
+ if (cond_branch) {
+ // loop prediction
+ bi->loopPred = getLoop(branch_pc, bi, useSpeculation,
instShiftAmt);
+
+ if ((loopUseCounter >= 0) && bi->loopPredValid) {
+ pred_taken = bi->loopPred;
+ bi->loopPredUsed = true;
+ }
+
+ if (useSpeculation) {
+ specLoopUpdate(pred_taken, bi);
+ }
+ }
+
+ return pred_taken;
+}
+
+void
+LoopPredictor::squash(ThreadID tid, BranchInfo *bi)
+{
+ if (bi->loopHit >= 0) {
+ int idx = finallindex(bi->loopIndex,
+ bi->loopIndexB,
+ bi->loopHit);
+ ltable[idx].currentIterSpec = bi->currentIter;
+ }
+}
+
+void
+LoopPredictor::squashLoop(BranchInfo* bi)
+{
+ if (bi->loopHit >= 0) {
+ int idx = finallindex(bi->loopIndex,
+ bi->loopIndexB,
+ bi->loopHit);
+ ltable[idx].currentIterSpec = bi->currentIter;
+ }
+}
+
+void
+LoopPredictor::updateStats(bool taken, BranchInfo* bi)
+{
+ if (taken == bi->loopPred) {
+ loopPredictorCorrect++;
+ } else {
+ loopPredictorWrong++;
+ }
+}
+
+void
+LoopPredictor::condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
+ bool tage_pred, BranchInfo* bi,
+ unsigned instShiftAmt, int rand0, int
rand1)
+{
+ if (useSpeculation) {
+ // recalculate loop prediction without speculation
+ // It is ok to overwrite the loop prediction fields in bi
+ // as the stats have already been updated with the previous
+ // values
+ bi->loopPred = getLoop(branch_pc, bi, false, instShiftAmt);
+ }
+
+ if (bi->loopPredValid) {
+ if (bi->predTaken != bi->loopPred) {
+ signedCtrUpdate(loopUseCounter,
+ (bi->loopPred == taken),
+ withLoopBits);
+ }
+ }
+
+ loopUpdate(branch_pc, taken, bi, tage_pred, rand0, rand1);
+}
+
+void
+LoopPredictor::regStats()
+{
+ loopPredictorCorrect
+ .name(name() + ".loopPredictorCorrect")
+ .desc("Number of times the loop predictor is the provider and "
+ "the prediction is correct");
+
+ loopPredictorWrong
+ .name(name() + ".loopPredictorWrong")
+ .desc("Number of times the loop predictor is the provider and "
+ "the prediction is wrong");
+}
diff --git a/src/cpu/pred/loop_predictor.hh b/src/cpu/pred/loop_predictor.hh
new file mode 100644
index 0000000..f31ea49
--- /dev/null
+++ b/src/cpu/pred/loop_predictor.hh
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2014 The University of Wisconsin
+ *
+ * Copyright (c) 2006 INRIA (Institut National de Recherche en
+ * Informatique et en Automatique / French National Research Institute
+ * for Computer Science and Applied Mathematics)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * 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;
+ * neither the name of the copyright holders 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
+ * OWNER 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.
+ *
+ * Authors: Vignyan Reddy, Dibakar Gope and Arthur Perais,
+ * from André Seznec's code.
+ */
+
+#ifndef __CPU_PRED_LOOP_PREDICTOR_HH__
+#define __CPU_PRED_LOOP_PREDICTOR_HH__
+
+#include "base/statistics.hh"
+#include "base/types.hh"
+
+class LoopPredictor {
+ protected:
+ /**
+ * Updates an unsigned counter based on up/down parameter
+ * @param ctr Reference to counter to update.
+ * @param up Boolean indicating if the counter is
incremented/decremented
+ * If true it is incremented, if false it is decremented
+ * @param nbits Counter width.
+ */
+ static inline void unsignedCtrUpdate(uint8_t &ctr, bool up, unsigned
nbits)
+ {
+ assert(nbits <= sizeof(uint8_t) << 3);
+ if (up) {
+ if (ctr < ((1 << nbits) - 1))
+ ctr++;
+ } else {
+ if (ctr)
+ ctr--;
+ }
+ }
+ static inline void signedCtrUpdate(int8_t &ctr, bool up, unsigned
nbits)
+ {
+ if (up) {
+ if (ctr < ((1 << (nbits - 1)) - 1))
+ ctr++;
+ } else {
+ if (ctr > -(1 << (nbits - 1)))
+ ctr--;
+ }
+ }
+ // Prediction Structures
+ // Loop Predictor Entry
+ struct LoopEntry
+ {
+ uint16_t numIter;
+ uint16_t currentIter;
+ uint16_t currentIterSpec; // only for useSpeculation
+ uint8_t confidence;
+ uint16_t tag;
+ uint8_t age;
+ bool dir; // only for useDirectionBit
+
+ LoopEntry() : numIter(0), currentIter(0), currentIterSpec(0),
+ confidence(0), tag(0), age(0), dir(0) { }
+ };
+
+ // Primary branch history entry
+ struct BranchInfo
+ {
+ uint16_t loopTag;
+ uint16_t currentIter;
+
+ bool loopPred;
+ bool loopPredValid;
+ bool loopPredUsed;
+ int loopIndex;
+ int loopIndexB; // only for useHashing
+ int loopHit;
+ bool predTaken;
+
+ BranchInfo()
+ : loopTag(0), currentIter(0),
+ loopPred(false),
+ loopPredValid(false), loopIndex(0), loopIndexB(0),
loopHit(0),
+ predTaken(false)
+ {}
+ };
+
+ /**
+ * Computes the index used to access the
+ * loop predictor.
+ * @param pc_in The unshifted branch PC.
+ * @param instShiftAmt Shift the pc by as many bits
+ */
+ int lindex(Addr pc_in, unsigned instShiftAmt) const;
+
+ /**
+ * Computes the index used to access the
+ * ltable structures.
+ * It may take hashing into account
+ * @param index Result of lindex function
+ * @param lowPcBits PC bits masked with set size
+ * @param way Way to be used
+ */
+ int finallindex(int lindex, int lowPcBits, int way) const;
+
+ /**
+ * Get a branch prediction from the loop
+ * predictor.
+ * @param pc The unshifted branch PC.
+ * @param bi Pointer to information on the
+ * prediction.
+ * @param speculative Use speculative number of iterations
+ * @param instShiftAmt Shift the pc by as many bits (if hashing is not
+ * used)
+ * @result the result of the prediction, if it could be predicted
+ */
+ bool getLoop(Addr pc, BranchInfo* bi, bool speculative,
+ unsigned instShiftAmt) const;
+
+ /**
+ * Updates the loop predictor.
+ * @param pc The unshifted branch PC.
+ * @param taken The actual branch outcome.
+ * @param bi Pointer to information on the
+ * prediction recorded at prediction time.
+ * @param tage_pred tage prediction of the branch
+ * @param random0 random value
+ * @param random1 random value
+ */
+ void loopUpdate(Addr pc, bool Taken, BranchInfo* bi, bool tage_pred,
+ int random0, int random1);
+
+ /**
+ * Speculatively updates the loop predictor
+ * iteration count (only for useSpeculation).
+ * @param taken The predicted branch outcome.
+ * @param bi Pointer to information on the prediction
+ * recorded at prediction time.
+ */
+ void specLoopUpdate(bool taken, BranchInfo* bi);
+
+ /**
+ * Update LTAGE for conditional branches.
+ * @param branch_pc The unshifted branch PC.
+ * @param taken Actual branch outcome.
+ * @param tage_pred Prediction from TAGE
+ * @param bi Pointer to information on the prediction
+ * recorded at prediction time.
+ * @param instShiftAmt Number of bits to shift instructions
+ * @param rand0 Random integer value
+ * @param rand1 Random integer value
+ */
+ void condBranchUpdate(
+ ThreadID tid, Addr branch_pc, bool taken, bool tage_pred,
+ BranchInfo* bi, unsigned instShiftAmt, int rand0, int rand1);
+
+ /**
+ * Get the loop prediction
+ * @param tid The thread ID to select the global
+ * histories to use.
+ * @param branch_pc The unshifted branch PC.
+ * @param cond_branch True if the branch is conditional.
+ * @param bi Reference to wrapping pointer to allow storing
+ * derived class prediction information in the base class.
+ * @param prev_pred_taken Result of the TAGE prediction
+ * @param instShiftAmt Shift the pc by as many bits
+ * @param instShiftAmt Shift the pc by as many bits
+ * @result the prediction, true if taken
+ */
+ bool loopPredict(
+ ThreadID tid, Addr branch_pc, bool cond_branch,
+ BranchInfo* bi, bool prev_pred_taken, unsigned instShiftAmt);
+
+ /**
+ * Update the stats
+ * @param taken Actual branch outcome
+ * @param bi Pointer to information on the prediction
+ * recorded at prediction time.
+ */
+ void updateStats(bool taken, BranchInfo* bi);
+
+ void squashLoop(BranchInfo * bi);
+
+ void squash(ThreadID tid, BranchInfo *bi);
+
+ virtual bool calcConf(int index) const;
+ virtual bool optionalAgeInc() const;
+
+ const unsigned logSizeLoopPred;
+ const unsigned loopTableAgeBits;
+ const unsigned loopTableConfidenceBits;
+ const unsigned loopTableTagBits;
+ const unsigned loopTableIterBits;
+ const unsigned logLoopTableAssoc;
+ const uint8_t confidenceThreshold;
+ const uint16_t loopTagMask;
+ const uint16_t loopNumIterMask;
+ const int loopSetMask;
+
+ LoopEntry *ltable;
+
+ int8_t loopUseCounter;
+ unsigned withLoopBits;
+
+ const bool useDirectionBit;
+ const bool useSpeculation;
+ const bool useHashing;
+ const bool restrictAllocation;
+ const unsigned initialLoopIter;
+ const unsigned initialLoopAge;
+ const bool optionalAgeReset;
+
+ // stats
+ Stats::Scalar loopPredictorCorrect;
+ Stats::Scalar loopPredictorWrong;
+
+ void init();
+ void regStats();
+
+ LoopPredictor(unsigned log_size_loop_pred,
+ unsigned loop_table_age_bits, unsigned loop_table_confidence_bits,
+ unsigned loop_table_tag_bits, unsigned loop_table_iter_bits,
+ unsigned log_loop_table_assoc, unsigned with_loop_bits,
+ bool use_direction_bit, bool use_speculation, bool use_hashing,
+ bool restrict_allocation, unsigned initial_loop_iter,
+ unsigned initial_loop_age, bool optional_age_reset);
+};
+#endif//__CPU_PRED_LOOP_PREDICTOR_HH__
diff --git a/src/cpu/pred/ltage.cc b/src/cpu/pred/ltage.cc
index 4c2ec9e..e615ffa 100644
--- a/src/cpu/pred/ltage.cc
+++ b/src/cpu/pred/ltage.cc
@@ -47,26 +47,21 @@
#include "debug/LTage.hh"
LTAGE::LTAGE(const LTAGEParams *params)
- : TAGE(params),
- logSizeLoopPred(params->logSizeLoopPred),
- loopTableAgeBits(params->loopTableAgeBits),
- loopTableConfidenceBits(params->loopTableConfidenceBits),
- loopTableTagBits(params->loopTableTagBits),
- loopTableIterBits(params->loopTableIterBits),
- logLoopTableAssoc(params->logLoopTableAssoc),
- confidenceThreshold((1 << loopTableConfidenceBits) - 1),
- loopTagMask((1 << loopTableTagBits) - 1),
- loopNumIterMask((1 << loopTableIterBits) - 1),
- loopSetMask((1 << (logSizeLoopPred - logLoopTableAssoc)) - 1),
- loopUseCounter(-1),
- withLoopBits(params->withLoopBits),
- useDirectionBit(params->useDirectionBit),
- useSpeculation(params->useSpeculation),
- useHashing(params->useHashing),
- restrictAllocation(params->restrictAllocation),
- initialLoopIter(params->initialLoopIter),
- initialLoopAge(params->initialLoopAge),
- optionalAgeReset(params->optionalAgeReset)
+ : TAGE(params), LoopPredictor(
+ params->logSizeLoopPred,
+ params->loopTableAgeBits,
+ params->loopTableConfidenceBits,
+ params->loopTableTagBits,
+ params->loopTableIterBits,
+ params->logLoopTableAssoc,
+ params->withLoopBits,
+ params->useDirectionBit,
+ params->useSpeculation,
+ params->useHashing,
+ params->restrictAllocation,
+ params->initialLoopIter,
+ params->initialLoopAge,
+ params->optionalAgeReset)
{
assert(initialLoopAge <= ((1 << loopTableAgeBits) - 1));
}
@@ -76,206 +71,9 @@
{
TAGE::init();
- // we use uint16_t type for these vales, so they cannot be more than
- // 16 bits
- assert(loopTableTagBits <= 16);
- assert(loopTableIterBits <= 16);
-
- assert(logSizeLoopPred >= logLoopTableAssoc);
-
- ltable = new LoopEntry[ULL(1) << logSizeLoopPred];
+ LoopPredictor::init();
}
-int
-LTAGE::lindex(Addr pc_in) const
-{
- // The loop table is implemented as a linear table
- // If associativity is N (N being 1 << logLoopTableAssoc),
- // the first N entries are for set 0, the next N entries are for set 1,
- // and so on.
- // Thus, this function calculates the set and then it gets left shifted
- // by logLoopTableAssoc in order to return the index of the first of
the
- // N entries of the set
- Addr pc = pc_in >> instShiftAmt;
- if (useHashing) {
- // copied from TAGE-SC-L
- // (http://www.jilp.org/cbp2016/code/AndreSeznecLimited.tar.gz)
- pc ^= pc_in;
- }
- return ((pc & loopSetMask) << logLoopTableAssoc);
-}
-
-int
-LTAGE::finallindex(int index, int lowPcBits, int way) const
-{
- // copied from TAGE-SC-L
- // (http://www.jilp.org/cbp2016/code/AndreSeznecLimited.tar.gz)
- return (useHashing ? (index ^ ((lowPcBits >> way) <<
logLoopTableAssoc)) :
- (index))
- + way;
-}
-
-//loop prediction: only used if high confidence
-bool
-LTAGE::getLoop(Addr pc, LTageBranchInfo* bi, bool speculative) const
-{
- bi->loopHit = -1;
- bi->loopPredValid = false;
- bi->loopIndex = lindex(pc);
-
- if (useHashing) {
- unsigned pcShift = logSizeLoopPred - logLoopTableAssoc;
- bi->loopIndexB = (pc >> pcShift) & loopSetMask;
- bi->loopTag = (pc >> pcShift) ^ (pc >> (pcShift +
loopTableTagBits));
- bi->loopTag &= loopTagMask;
- } else {
- unsigned pcShift = instShiftAmt + logSizeLoopPred -
logLoopTableAssoc;
- bi->loopTag = (pc >> pcShift) & loopTagMask;
- // bi->loopIndexB is not used without hash
- }
-
- for (int i = 0; i < (1 << logLoopTableAssoc); i++) {
- int idx = finallindex(bi->loopIndex, bi->loopIndexB, i);
- if (ltable[idx].tag == bi->loopTag) {
- bi->loopHit = i;
- bi->loopPredValid = calcConf(idx);
-
- uint16_t iter = speculative ? ltable[idx].currentIterSpec
- : ltable[idx].currentIter;
-
- if ((iter + 1) == ltable[idx].numIter) {
- return useDirectionBit ? !(ltable[idx].dir) : false;
- } else {
- return useDirectionBit ? (ltable[idx].dir) : true;
- }
- }
- }
- return false;
-}
-
-bool
-LTAGE::calcConf(int index) const
-{
- return ltable[index].confidence == confidenceThreshold;
-}
-
-void
-LTAGE::specLoopUpdate(bool taken, LTageBranchInfo* bi)
-{
- if (bi->loopHit>=0) {
- int index = finallindex(bi->loopIndex, bi->loopIndexB,
bi->loopHit);
- if (taken != ltable[index].dir) {
- ltable[index].currentIterSpec = 0;
- } else {
- ltable[index].currentIterSpec =
- (ltable[index].currentIterSpec + 1) & loopNumIterMask;
- }
- }
-}
-
-bool
-LTAGE::optionalAgeInc() const
-{
- return false;
-}
-
-void
-LTAGE::loopUpdate(Addr pc, bool taken, LTageBranchInfo* bi)
-{
- int idx = finallindex(bi->loopIndex, bi->loopIndexB, bi->loopHit);
- if (bi->loopHit >= 0) {
- //already a hit
- if (bi->loopPredValid) {
- if (taken != bi->loopPred) {
- // free the entry
- ltable[idx].numIter = 0;
- ltable[idx].age = 0;
- ltable[idx].confidence = 0;
- ltable[idx].currentIter = 0;
- return;
- } else if (bi->loopPred != bi->tagePred || optionalAgeInc()) {
- DPRINTF(LTage, "Loop Prediction success:%lx\n",pc);
- unsignedCtrUpdate(ltable[idx].age, true, loopTableAgeBits);
- }
- }
-
- ltable[idx].currentIter =
- (ltable[idx].currentIter + 1) & loopNumIterMask;
- if (ltable[idx].currentIter > ltable[idx].numIter) {
- ltable[idx].confidence = 0;
- if (ltable[idx].numIter != 0) {
- // free the entry
- ltable[idx].numIter = 0;
- if (optionalAgeReset) {
- ltable[idx].age = 0;
- }
- ltable[idx].confidence = 0;
- }
- }
-
- if (taken != (useDirectionBit ? ltable[idx].dir : true)) {
- if (ltable[idx].currentIter == ltable[idx].numIter) {
- DPRINTF(LTage, "Loop End predicted successfully:%lx\n",
pc);
-
- unsignedCtrUpdate(ltable[idx].confidence, true,
- loopTableConfidenceBits);
- //just do not predict when the loop count is 1 or 2
- if (ltable[idx].numIter < 3) {
- // free the entry
- ltable[idx].dir = taken; // ignored if no
useDirectionBit
- ltable[idx].numIter = 0;
- ltable[idx].age = 0;
- ltable[idx].confidence = 0;
- }
- } else {
- DPRINTF(LTage, "Loop End predicted incorrectly:%lx\n", pc);
- if (ltable[idx].numIter == 0) {
- // first complete nest;
- ltable[idx].confidence = 0;
- ltable[idx].numIter = ltable[idx].currentIter;
- } else {
- //not the same number of iterations as last time: free
the
- //entry
- ltable[idx].numIter = 0;
- if (optionalAgeReset) {
- ltable[idx].age = 0;
- }
- ltable[idx].confidence = 0;
- }
- }
- ltable[idx].currentIter = 0;
- }
-
- } else if (useDirectionBit ? (bi->predTaken != taken) : taken) {
- if ((getRandom() & 3) == 0 || ! restrictAllocation) {
- //try to allocate an entry on taken branch
- int nrand = getRandom();
- for (int i = 0; i < (1 << logLoopTableAssoc); i++) {
- int loop_hit = (nrand + i) & ((1 << logLoopTableAssoc) -
1);
- idx = finallindex(bi->loopIndex, bi->loopIndexB, loop_hit);
- if (ltable[idx].age == 0) {
- DPRINTF(LTage,
- "Allocating loop pred entry for branch %lx\n",
- pc);
- ltable[idx].dir = !taken; // ignored if no
useDirectionBit
- ltable[idx].tag = bi->loopTag;
- ltable[idx].numIter = 0;
- ltable[idx].age = initialLoopAge;
- ltable[idx].confidence = 0;
- ltable[idx].currentIter = initialLoopIter;
- break;
-
- } else {
- ltable[idx].age--;
- }
- if (restrictAllocation) {
- break;
- }
- }
- }
- }
-
-}
//prediction
bool
@@ -286,37 +84,22 @@
bool pred_taken = tagePredict(tid, branch_pc, cond_branch, bi);
- pred_taken = loopPredict(tid, branch_pc, cond_branch, bi, pred_taken);
+ pred_taken = loopPredict(tid, branch_pc, cond_branch, bi, pred_taken,
+ instShiftAmt);
- // record final prediction
- bi->predTaken = pred_taken;
-
- return pred_taken;
-}
-
-bool
-LTAGE::loopPredict(ThreadID tid, Addr branch_pc, bool cond_branch,
- LTageBranchInfo* bi, bool prev_pred_taken)
-{
- bool pred_taken = prev_pred_taken;
if (cond_branch) {
- // loop prediction
- bi->loopPred = getLoop(branch_pc, bi, useSpeculation);
-
- if ((loopUseCounter >= 0) && bi->loopPredValid) {
- pred_taken = bi->loopPred;
+ if (bi->loopPredUsed) {
bi->provider = LOOP;
}
DPRINTF(LTage, "Predict for %lx: taken?:%d, loopTaken?:%d, "
"loopValid?:%d, loopUseCounter:%d, tagePred:%d,
altPred:%d\n",
branch_pc, pred_taken, bi->loopPred, bi->loopPredValid,
loopUseCounter, bi->tagePred, bi->altTaken);
-
- if (useSpeculation) {
- specLoopUpdate(pred_taken, bi);
- }
}
+ // record final prediction
+ bi->predTaken = pred_taken;
+
return pred_taken;
}
@@ -326,23 +109,8 @@
{
LTageBranchInfo* bi = static_cast<LTageBranchInfo*>(tage_bi);
- if (useSpeculation) {
- // recalculate loop prediction without speculation
- // It is ok to overwrite the loop prediction fields in bi
- // as the stats have already been updated with the previous
- // values
- bi->loopPred = getLoop(branch_pc, bi, false);
- }
-
- if (bi->loopPredValid) {
- if (bi->predTaken != bi->loopPred) {
- ctrUpdate(loopUseCounter,
- (bi->loopPred == taken),
- withLoopBits);
- }
- }
-
- loopUpdate(branch_pc, taken, bi);
+ LoopPredictor::condBranchUpdate(tid, branch_pc, taken, bi->tagePred,
bi,
+ instShiftAmt, getRandom(), getRandom());
TAGE::condBranchUpdate(tid, branch_pc, taken, bi, nrand, corrTarget);
}
@@ -354,19 +122,8 @@
LTageBranchInfo* bi = (LTageBranchInfo*)(bp_history);
- squashLoop(bi);
-}
-
-void
-LTAGE::squashLoop(LTageBranchInfo* bi)
-{
if (bi->condBranch) {
- if (bi->loopHit >= 0) {
- int idx = finallindex(bi->loopIndex,
- bi->loopIndexB,
- bi->loopHit);
- ltable[idx].currentIterSpec = bi->currentIter;
- }
+ squashLoop(bi);
}
}
@@ -374,19 +131,14 @@
LTAGE::squash(ThreadID tid, void *bp_history)
{
LTageBranchInfo* bi = (LTageBranchInfo*)(bp_history);
+
if (bi->condBranch) {
- if (bi->loopHit >= 0) {
- int idx = finallindex(bi->loopIndex,
- bi->loopIndexB,
- bi->loopHit);
- ltable[idx].currentIterSpec = bi->currentIter;
- }
+ LoopPredictor::squash(tid, bi);
}
TAGE::squash(tid, bp_history);
}
-
void
LTAGE::updateStats(bool taken, TageBranchInfo* bi)
{
@@ -395,34 +147,18 @@
LTageBranchInfo * ltage_bi = static_cast<LTageBranchInfo *>(bi);
if (ltage_bi->provider == LOOP) {
- if (taken == ltage_bi->loopPred) {
- loopPredictorCorrect++;
- } else {
- loopPredictorWrong++;
- }
+ LoopPredictor::updateStats(taken, ltage_bi);
}
}
-
-
void
LTAGE::regStats()
{
TAGE::regStats();
- loopPredictorCorrect
- .name(name() + ".loopPredictorCorrect")
- .desc("Number of times the loop predictor is the provider and "
- "the prediction is correct");
-
- loopPredictorWrong
- .name(name() + ".loopPredictorWrong")
- .desc("Number of times the loop predictor is the provider and "
- "the prediction is wrong");
+ LoopPredictor::regStats();
}
-
-
LTAGE*
LTAGEParams::create()
{
diff --git a/src/cpu/pred/ltage.hh b/src/cpu/pred/ltage.hh
index 39362d2..413a80b 100644
--- a/src/cpu/pred/ltage.hh
+++ b/src/cpu/pred/ltage.hh
@@ -56,10 +56,11 @@
#include <vector>
#include "base/types.hh"
+#include "cpu/pred/loop_predictor.hh"
#include "cpu/pred/tage.hh"
#include "params/LTAGE.hh"
-class LTAGE: public TAGE
+class LTAGE: public TAGE, public LoopPredictor
{
public:
LTAGE(const LTAGEParams *params);
@@ -71,96 +72,22 @@
virtual void regStats() override;
protected:
- // Prediction Structures
- // Loop Predictor Entry
- struct LoopEntry
- {
- uint16_t numIter;
- uint16_t currentIter;
- uint16_t currentIterSpec; // only for useSpeculation
- uint8_t confidence;
- uint16_t tag;
- uint8_t age;
- bool dir; // only for useDirectionBit
-
- LoopEntry() : numIter(0), currentIter(0), currentIterSpec(0),
- confidence(0), tag(0), age(0), dir(0) { }
- };
// more provider types
enum {
LOOP = LAST_TAGE_PROVIDER_TYPE + 1,
LAST_LTAGE_PROVIDER_TYPE = LOOP
};
-
// Primary branch history entry
- struct LTageBranchInfo : public TageBranchInfo
+ struct LTageBranchInfo : public TageBranchInfo,
+ public LoopPredictor::BranchInfo
{
- uint16_t loopTag;
- uint16_t currentIter;
-
- bool loopPred;
- bool loopPredValid;
- int loopIndex;
- int loopIndexB; // only for useHashing
- int loopHit;
- bool predTaken;
-
- LTageBranchInfo(int sz)
- : TageBranchInfo(sz),
- loopTag(0), currentIter(0),
- loopPred(false),
- loopPredValid(false), loopIndex(0), loopIndexB(0),
loopHit(0),
- predTaken(false)
+ LTageBranchInfo(int sz) : TageBranchInfo(sz),
+ LoopPredictor::BranchInfo()
{}
};
/**
- * Computes the index used to access the
- * loop predictor.
- * @param pc_in The unshifted branch PC.
- */
- int lindex(Addr pc_in) const;
-
- /**
- * Computes the index used to access the
- * ltable structures.
- * It may take hashing into account
- * @param index Result of lindex function
- * @param lowPcBits PC bits masked with set size
- * @param way Way to be used
- */
- int finallindex(int lindex, int lowPcBits, int way) const;
-
- /**
- * Get a branch prediction from the loop
- * predictor.
- * @param pc The unshifted branch PC.
- * @param bi Pointer to information on the
- * prediction.
- * @param speculative Use speculative number of iterations
- */
- bool getLoop(Addr pc, LTageBranchInfo* bi, bool speculative) const;
-
- /**
- * Updates the loop predictor.
- * @param pc The unshifted branch PC.
- * @param taken The actual branch outcome.
- * @param bi Pointer to information on the
- * prediction recorded at prediction time.
- */
- void loopUpdate(Addr pc, bool Taken, LTageBranchInfo* bi);
-
- /**
- * Speculatively updates the loop predictor
- * iteration count (only for useSpeculation).
- * @param taken The predicted branch outcome.
- * @param bi Pointer to information on the prediction
- * recorded at prediction time.
- */
- void specLoopUpdate(bool taken, LTageBranchInfo* bi);
-
- /**
* Update LTAGE for conditional branches.
* @param branch_pc The unshifted branch PC.
* @param taken Actual branch outcome.
@@ -187,20 +114,6 @@
ThreadID tid, Addr branch_pc, bool cond_branch, void* &b) override;
/**
- * Get the loop prediction
- * @param tid The thread ID to select the global
- * histories to use.
- * @param branch_pc The unshifted branch PC.
- * @param cond_branch True if the branch is conditional.
- * @param bi Reference to wrapping pointer to allow storing
- * derived class prediction information in the base class.
- * @param prev_pred_taken Result of the TAGE prediction
- */
- bool loopPredict(
- ThreadID tid, Addr branch_pc, bool cond_branch,
- LTageBranchInfo* bi, bool prev_pred_taken);
-
- /**
* Restores speculatively updated path and direction histories.
* Also recomputes compressed (folded) histories based on the
* correct branch outcome.
@@ -224,38 +137,6 @@
*/
virtual void updateStats(bool taken, TageBranchInfo* bi) override;
- void squashLoop(LTageBranchInfo * bi);
-
- virtual bool calcConf(int index) const;
- virtual bool optionalAgeInc() const;
-
- const unsigned logSizeLoopPred;
- const unsigned loopTableAgeBits;
- const unsigned loopTableConfidenceBits;
- const unsigned loopTableTagBits;
- const unsigned loopTableIterBits;
- const unsigned logLoopTableAssoc;
- const uint8_t confidenceThreshold;
- const uint16_t loopTagMask;
- const uint16_t loopNumIterMask;
- const int loopSetMask;
-
- LoopEntry *ltable;
-
- int8_t loopUseCounter;
- unsigned withLoopBits;
-
- const bool useDirectionBit;
- const bool useSpeculation;
- const bool useHashing;
- const bool restrictAllocation;
- const unsigned initialLoopIter;
- const unsigned initialLoopAge;
- const bool optionalAgeReset;
-
- // stats
- Stats::Scalar loopPredictorCorrect;
- Stats::Scalar loopPredictorWrong;
};
#endif // __CPU_PRED_LTAGE
diff --git a/src/cpu/pred/tage_sc_l.cc b/src/cpu/pred/tage_sc_l.cc
index 25c1a1a..16d3a34 100644
--- a/src/cpu/pred/tage_sc_l.cc
+++ b/src/cpu/pred/tage_sc_l.cc
@@ -405,7 +405,8 @@
bool pred_taken = tagePredict(tid, branch_pc, cond_branch, bi);
- pred_taken = loopPredict(tid, branch_pc, cond_branch, bi, pred_taken);
+ pred_taken = loopPredict(tid, branch_pc, cond_branch, bi, pred_taken,
+ instShiftAmt);
pred_taken = scPredict(tid, branch_pc, cond_branch, bi, pred_taken);
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/15775
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I60ad079a2c49b00a1f84d5cfd3611631883a4b57
Gerrit-Change-Number: 15775
Gerrit-PatchSet: 1
Gerrit-Owner: Javier Bueno Hedo <javier.bu...@metempsy.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev