| /* |
| * 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/random.hh" |
| #include "debug/LTage.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() const |
| { |
| return false; |
| } |
| |
| void |
| LoopPredictor::loopUpdate(Addr pc, bool taken, BranchInfo* bi, bool tage_pred) |
| { |
| 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()) { |
| 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; |
| } |
| } |
| } |
| |
| 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 ((random_mt.random<int>() & 3) == 0 || !restrictAllocation) { |
| //try to allocate an entry on taken branch |
| int nrand = random_mt.random<int>(); |
| 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; |
| } |
| } |
| } |
| } |
| } |
| |
| 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) |
| { |
| 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); |
| } |
| |
| 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); |
| } |