summaryrefslogtreecommitdiff
path: root/src/cpu/pred/loop_predictor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/pred/loop_predictor.cc')
-rw-r--r--src/cpu/pred/loop_predictor.cc361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/cpu/pred/loop_predictor.cc b/src/cpu/pred/loop_predictor.cc
new file mode 100644
index 000000000..2e709f392
--- /dev/null
+++ b/src/cpu/pred/loop_predictor.cc
@@ -0,0 +1,361 @@
+/*
+ * 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 "params/LoopPredictor.hh"
+
+LoopPredictor::LoopPredictor(LoopPredictorParams *p)
+ : SimObject(p), logSizeLoopPred(p->logSizeLoopPred),
+ loopTableAgeBits(p->loopTableAgeBits),
+ loopTableConfidenceBits(p->loopTableConfidenceBits),
+ loopTableTagBits(p->loopTableTagBits),
+ loopTableIterBits(p->loopTableIterBits),
+ logLoopTableAssoc(p->logLoopTableAssoc),
+ confidenceThreshold((1 << loopTableConfidenceBits) - 1),
+ loopTagMask((1 << loopTableTagBits) - 1),
+ loopNumIterMask((1 << loopTableIterBits) - 1),
+ loopSetMask((1 << (logSizeLoopPred - logLoopTableAssoc)) - 1),
+ loopUseCounter(-1),
+ withLoopBits(p->withLoopBits),
+ useDirectionBit(p->useDirectionBit),
+ useSpeculation(p->useSpeculation),
+ useHashing(p->useHashing),
+ restrictAllocation(p->restrictAllocation),
+ initialLoopIter(p->initialLoopIter),
+ initialLoopAge(p->initialLoopAge),
+ optionalAgeReset(p->optionalAgeReset)
+{
+ 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];
+}
+
+LoopPredictor::BranchInfo*
+LoopPredictor::makeBranchInfo()
+{
+ return new BranchInfo();
+}
+
+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) {
+ pc ^= pc_in;
+ }
+ return ((pc & loopSetMask) << logLoopTableAssoc);
+}
+
+int
+LoopPredictor::finallindex(int index, int lowPcBits, int way) const
+{
+ 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(int nrand) const
+{
+ return false;
+}
+
+void
+LoopPredictor::loopUpdate(Addr pc, bool taken, BranchInfo* bi, bool tage_pred,
+ int random0, int random1, int random2)
+{
+ 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(random0)) {
+ 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 {
+ 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 ((random2 & 3) == 0 || !restrictAllocation) {
+ //try to allocate an entry on taken branch
+ int nrand = random1;
+ 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,
+ int rand2)
+{
+ 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, rand2);
+}
+
+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");
+}
+
+LoopPredictor *
+LoopPredictorParams::create()
+{
+ return new LoopPredictor(this);
+}