| /* |
| * Copyright (c) 2014 The Regents of The University of Michigan |
| * 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: Anthony Gutierrez |
| */ |
| |
| /* @file |
| * Implementation of a bi-mode branch predictor |
| */ |
| |
| #include "cpu/pred/bi_mode.hh" |
| |
| #include "base/bitfield.hh" |
| #include "base/intmath.hh" |
| |
| BiModeBP::BiModeBP(const BiModeBPParams *params) |
| : BPredUnit(params), |
| globalHistoryReg(params->numThreads, 0), |
| globalHistoryBits(ceilLog2(params->globalPredictorSize)), |
| choicePredictorSize(params->choicePredictorSize), |
| choiceCtrBits(params->choiceCtrBits), |
| globalPredictorSize(params->globalPredictorSize), |
| globalCtrBits(params->globalCtrBits) |
| { |
| if (!isPowerOf2(choicePredictorSize)) |
| fatal("Invalid choice predictor size.\n"); |
| if (!isPowerOf2(globalPredictorSize)) |
| fatal("Invalid global history predictor size.\n"); |
| |
| choiceCounters.resize(choicePredictorSize); |
| takenCounters.resize(globalPredictorSize); |
| notTakenCounters.resize(globalPredictorSize); |
| |
| for (int i = 0; i < choicePredictorSize; ++i) { |
| choiceCounters[i].setBits(choiceCtrBits); |
| } |
| for (int i = 0; i < globalPredictorSize; ++i) { |
| takenCounters[i].setBits(globalCtrBits); |
| notTakenCounters[i].setBits(globalCtrBits); |
| } |
| |
| historyRegisterMask = mask(globalHistoryBits); |
| choiceHistoryMask = choicePredictorSize - 1; |
| globalHistoryMask = globalPredictorSize - 1; |
| |
| choiceThreshold = (ULL(1) << (choiceCtrBits - 1)) - 1; |
| takenThreshold = (ULL(1) << (globalCtrBits - 1)) - 1; |
| notTakenThreshold = (ULL(1) << (globalCtrBits - 1)) - 1; |
| } |
| |
| /* |
| * For an unconditional branch we set its history such that |
| * everything is set to taken. I.e., its choice predictor |
| * chooses the taken array and the taken array predicts taken. |
| */ |
| void |
| BiModeBP::uncondBranch(ThreadID tid, Addr pc, void * &bpHistory) |
| { |
| BPHistory *history = new BPHistory; |
| history->globalHistoryReg = globalHistoryReg[tid]; |
| history->takenUsed = true; |
| history->takenPred = true; |
| history->notTakenPred = true; |
| history->finalPred = true; |
| bpHistory = static_cast<void*>(history); |
| updateGlobalHistReg(tid, true); |
| } |
| |
| void |
| BiModeBP::squash(ThreadID tid, void *bpHistory) |
| { |
| BPHistory *history = static_cast<BPHistory*>(bpHistory); |
| globalHistoryReg[tid] = history->globalHistoryReg; |
| |
| delete history; |
| } |
| |
| /* |
| * Here we lookup the actual branch prediction. We use the PC to |
| * identify the bias of a particular branch, which is based on the |
| * prediction in the choice array. A hash of the global history |
| * register and a branch's PC is used to index into both the taken |
| * and not-taken predictors, which both present a prediction. The |
| * choice array's prediction is used to select between the two |
| * direction predictors for the final branch prediction. |
| */ |
| bool |
| BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bpHistory) |
| { |
| unsigned choiceHistoryIdx = ((branchAddr >> instShiftAmt) |
| & choiceHistoryMask); |
| unsigned globalHistoryIdx = (((branchAddr >> instShiftAmt) |
| ^ globalHistoryReg[tid]) |
| & globalHistoryMask); |
| |
| assert(choiceHistoryIdx < choicePredictorSize); |
| assert(globalHistoryIdx < globalPredictorSize); |
| |
| bool choicePrediction = choiceCounters[choiceHistoryIdx].read() |
| > choiceThreshold; |
| bool takenGHBPrediction = takenCounters[globalHistoryIdx].read() |
| > takenThreshold; |
| bool notTakenGHBPrediction = notTakenCounters[globalHistoryIdx].read() |
| > notTakenThreshold; |
| bool finalPrediction; |
| |
| BPHistory *history = new BPHistory; |
| history->globalHistoryReg = globalHistoryReg[tid]; |
| history->takenUsed = choicePrediction; |
| history->takenPred = takenGHBPrediction; |
| history->notTakenPred = notTakenGHBPrediction; |
| |
| if (choicePrediction) { |
| finalPrediction = takenGHBPrediction; |
| } else { |
| finalPrediction = notTakenGHBPrediction; |
| } |
| |
| history->finalPred = finalPrediction; |
| bpHistory = static_cast<void*>(history); |
| updateGlobalHistReg(tid, finalPrediction); |
| |
| return finalPrediction; |
| } |
| |
| void |
| BiModeBP::btbUpdate(ThreadID tid, Addr branchAddr, void * &bpHistory) |
| { |
| globalHistoryReg[tid] &= (historyRegisterMask & ~ULL(1)); |
| } |
| |
| /* Only the selected direction predictor will be updated with the final |
| * outcome; the status of the unselected one will not be altered. The choice |
| * predictor is always updated with the branch outcome, except when the |
| * choice is opposite to the branch outcome but the selected counter of |
| * the direction predictors makes a correct final prediction. |
| */ |
| void |
| BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken, void *bpHistory, |
| bool squashed, const StaticInstPtr & inst, Addr corrTarget) |
| { |
| assert(bpHistory); |
| |
| BPHistory *history = static_cast<BPHistory*>(bpHistory); |
| |
| // We do not update the counters speculatively on a squash. |
| // We just restore the global history register. |
| if (squashed) { |
| globalHistoryReg[tid] = (history->globalHistoryReg << 1) | taken; |
| return; |
| } |
| |
| unsigned choiceHistoryIdx = ((branchAddr >> instShiftAmt) |
| & choiceHistoryMask); |
| unsigned globalHistoryIdx = (((branchAddr >> instShiftAmt) |
| ^ history->globalHistoryReg) |
| & globalHistoryMask); |
| |
| assert(choiceHistoryIdx < choicePredictorSize); |
| assert(globalHistoryIdx < globalPredictorSize); |
| |
| if (history->takenUsed) { |
| // if the taken array's prediction was used, update it |
| if (taken) { |
| takenCounters[globalHistoryIdx].increment(); |
| } else { |
| takenCounters[globalHistoryIdx].decrement(); |
| } |
| } else { |
| // if the not-taken array's prediction was used, update it |
| if (taken) { |
| notTakenCounters[globalHistoryIdx].increment(); |
| } else { |
| notTakenCounters[globalHistoryIdx].decrement(); |
| } |
| } |
| |
| if (history->finalPred == taken) { |
| /* If the final prediction matches the actual branch's |
| * outcome and the choice predictor matches the final |
| * outcome, we update the choice predictor, otherwise it |
| * is not updated. While the designers of the bi-mode |
| * predictor don't explicity say why this is done, one |
| * can infer that it is to preserve the choice predictor's |
| * bias with respect to the branch being predicted; afterall, |
| * the whole point of the bi-mode predictor is to identify the |
| * atypical case when a branch deviates from its bias. |
| */ |
| if (history->finalPred == history->takenUsed) { |
| if (taken) { |
| choiceCounters[choiceHistoryIdx].increment(); |
| } else { |
| choiceCounters[choiceHistoryIdx].decrement(); |
| } |
| } |
| } else { |
| // always update the choice predictor on an incorrect prediction |
| if (taken) { |
| choiceCounters[choiceHistoryIdx].increment(); |
| } else { |
| choiceCounters[choiceHistoryIdx].decrement(); |
| } |
| } |
| |
| delete history; |
| } |
| |
| void |
| BiModeBP::updateGlobalHistReg(ThreadID tid, bool taken) |
| { |
| globalHistoryReg[tid] = taken ? (globalHistoryReg[tid] << 1) | 1 : |
| (globalHistoryReg[tid] << 1); |
| globalHistoryReg[tid] &= historyRegisterMask; |
| } |
| |
| BiModeBP* |
| BiModeBPParams::create() |
| { |
| return new BiModeBP(this); |
| } |