bpred_unit.cc revision 10785:f56c10663a01
1/*
2 * Copyright (c) 2011-2012, 2014 ARM Limited
3 * Copyright (c) 2010 The University of Edinburgh
4 * Copyright (c) 2012 Mark D. Hill and David A. Wood
5 * All rights reserved
6 *
7 * The license below extends only to copyright in the software and shall
8 * not be construed as granting a license to any other intellectual
9 * property including but not limited to intellectual property relating
10 * to a hardware implementation of the functionality of the software
11 * licensed hereunder.  You may use the software subject to the license
12 * terms below provided that you ensure that this notice is replicated
13 * unmodified and in its entirety in all distributions of the software,
14 * modified or unmodified, in source code or in binary form.
15 *
16 * Copyright (c) 2004-2005 The Regents of The University of Michigan
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met: redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer;
23 * redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution;
26 * neither the name of the copyright holders nor the names of its
27 * contributors may be used to endorse or promote products derived from
28 * this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * Authors: Kevin Lim
43 */
44
45#include "cpu/pred/bpred_unit.hh"
46
47#include <algorithm>
48
49#include "arch/isa_traits.hh"
50#include "arch/types.hh"
51#include "arch/utility.hh"
52#include "base/trace.hh"
53#include "config/the_isa.hh"
54#include "debug/Branch.hh"
55
56BPredUnit::BPredUnit(const Params *params)
57    : SimObject(params),
58      numThreads(params->numThreads),
59      predHist(numThreads),
60      BTB(params->BTBEntries,
61          params->BTBTagSize,
62          params->instShiftAmt),
63      RAS(numThreads),
64      instShiftAmt(params->instShiftAmt)
65{
66    for (auto& r : RAS)
67        r.init(params->RASSize);
68}
69
70void
71BPredUnit::regStats()
72{
73    lookups
74        .name(name() + ".lookups")
75        .desc("Number of BP lookups")
76        ;
77
78    condPredicted
79        .name(name() + ".condPredicted")
80        .desc("Number of conditional branches predicted")
81        ;
82
83    condIncorrect
84        .name(name() + ".condIncorrect")
85        .desc("Number of conditional branches incorrect")
86        ;
87
88    BTBLookups
89        .name(name() + ".BTBLookups")
90        .desc("Number of BTB lookups")
91        ;
92
93    BTBHits
94        .name(name() + ".BTBHits")
95        .desc("Number of BTB hits")
96        ;
97
98    BTBCorrect
99        .name(name() + ".BTBCorrect")
100        .desc("Number of correct BTB predictions (this stat may not "
101              "work properly.")
102        ;
103
104    BTBHitPct
105        .name(name() + ".BTBHitPct")
106        .desc("BTB Hit Percentage")
107        .precision(6);
108    BTBHitPct = (BTBHits / BTBLookups) * 100;
109
110    usedRAS
111        .name(name() + ".usedRAS")
112        .desc("Number of times the RAS was used to get a target.")
113        ;
114
115    RASIncorrect
116        .name(name() + ".RASInCorrect")
117        .desc("Number of incorrect RAS predictions.")
118        ;
119}
120
121ProbePoints::PMUUPtr
122BPredUnit::pmuProbePoint(const char *name)
123{
124    ProbePoints::PMUUPtr ptr;
125    ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
126
127    return ptr;
128}
129
130void
131BPredUnit::regProbePoints()
132{
133    ppBranches = pmuProbePoint("Branches");
134    ppMisses = pmuProbePoint("Misses");
135}
136
137void
138BPredUnit::drainSanityCheck() const
139{
140    // We shouldn't have any outstanding requests when we resume from
141    // a drained system.
142    for (const auto& ph M5_VAR_USED : predHist)
143        assert(ph.empty());
144}
145
146bool
147BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
148                   TheISA::PCState &pc, ThreadID tid)
149{
150    // See if branch predictor predicts taken.
151    // If so, get its target addr either from the BTB or the RAS.
152    // Save off record of branch stuff so the RAS can be fixed
153    // up once it's done.
154
155    bool pred_taken = false;
156    TheISA::PCState target = pc;
157
158    ++lookups;
159    ppBranches->notify(1);
160
161    void *bp_history = NULL;
162
163    if (inst->isUncondCtrl()) {
164        DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
165        pred_taken = true;
166        // Tell the BP there was an unconditional branch.
167        uncondBranch(pc.instAddr(), bp_history);
168    } else {
169        ++condPredicted;
170        pred_taken = lookup(pc.instAddr(), bp_history);
171
172        DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
173                " predicted %i for PC %s\n", tid, seqNum,  pred_taken, pc);
174    }
175
176    DPRINTF(Branch, "[tid:%i]: [sn:%i] Creating prediction history "
177            "for PC %s\n", tid, seqNum, pc);
178
179    PredictorHistory predict_record(seqNum, pc.instAddr(),
180                                    pred_taken, bp_history, tid);
181
182    // Now lookup in the BTB or RAS.
183    if (pred_taken) {
184        if (inst->isReturn()) {
185            ++usedRAS;
186            predict_record.wasReturn = true;
187            // If it's a function return call, then look up the address
188            // in the RAS.
189            TheISA::PCState rasTop = RAS[tid].top();
190            target = TheISA::buildRetPC(pc, rasTop);
191
192            // Record the top entry of the RAS, and its index.
193            predict_record.usedRAS = true;
194            predict_record.RASIndex = RAS[tid].topIdx();
195            predict_record.RASTarget = rasTop;
196
197            RAS[tid].pop();
198
199            DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
200                    "RAS predicted target: %s, RAS index: %i.\n",
201                    tid, pc, target, predict_record.RASIndex);
202        } else {
203            ++BTBLookups;
204
205            if (inst->isCall()) {
206                RAS[tid].push(pc);
207                predict_record.pushedRAS = true;
208
209                // Record that it was a call so that the top RAS entry can
210                // be popped off if the speculation is incorrect.
211                predict_record.wasCall = true;
212
213                DPRINTF(Branch, "[tid:%i]: Instruction %s was a "
214                        "call, adding %s to the RAS index: %i.\n",
215                        tid, pc, pc, RAS[tid].topIdx());
216            }
217
218            if (BTB.valid(pc.instAddr(), tid)) {
219                ++BTBHits;
220
221                // If it's not a return, use the BTB to get the target addr.
222                target = BTB.lookup(pc.instAddr(), tid);
223
224                DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
225                        " target is %s.\n", tid, pc, target);
226
227            } else {
228                DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
229                        "valid entry.\n",tid);
230                pred_taken = false;
231                // The Direction of the branch predictor is altered because the
232                // BTB did not have an entry
233                // The predictor needs to be updated accordingly
234                if (!inst->isCall() && !inst->isReturn()) {
235                      btbUpdate(pc.instAddr(), bp_history);
236                      DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
237                              " called for %s\n", tid, seqNum, pc);
238                } else if (inst->isCall() && !inst->isUncondCtrl()) {
239                      RAS[tid].pop();
240                      predict_record.pushedRAS = false;
241                }
242                TheISA::advancePC(target, inst);
243            }
244        }
245    } else {
246        if (inst->isReturn()) {
247           predict_record.wasReturn = true;
248        }
249        TheISA::advancePC(target, inst);
250    }
251
252    pc = target;
253
254    predHist[tid].push_front(predict_record);
255
256    DPRINTF(Branch, "[tid:%i]: [sn:%i]: History entry added."
257            "predHist.size(): %i\n", tid, seqNum, predHist[tid].size());
258
259    return pred_taken;
260}
261
262bool
263BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
264                          int asid, TheISA::PCState &instPC,
265                          TheISA::PCState &predPC, ThreadID tid)
266{
267    // See if branch predictor predicts taken.
268    // If so, get its target addr either from the BTB or the RAS.
269    // Save off record of branch stuff so the RAS can be fixed
270    // up once it's done.
271
272    using TheISA::MachInst;
273
274    bool pred_taken = false;
275    TheISA::PCState target;
276
277    ++lookups;
278    ppBranches->notify(1);
279
280    DPRINTF(Branch, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
281            "prediction\n", tid, seqNum,
282            inst->disassemble(instPC.instAddr()), instPC);
283
284    void *bp_history = NULL;
285
286    if (inst->isUncondCtrl()) {
287        DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
288        pred_taken = true;
289        // Tell the BP there was an unconditional branch.
290        uncondBranch(instPC.instAddr(), bp_history);
291
292        if (inst->isReturn() && RAS[tid].empty()) {
293            DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
294                    "false.\n", tid);
295            pred_taken = false;
296        }
297    } else {
298        ++condPredicted;
299
300        pred_taken = lookup(predPC.instAddr(), bp_history);
301    }
302
303    PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
304                                    bp_history, tid);
305
306    // Now lookup in the BTB or RAS.
307    if (pred_taken) {
308        if (inst->isReturn()) {
309            ++usedRAS;
310
311            // If it's a function return call, then look up the address
312            // in the RAS.
313            TheISA::PCState rasTop = RAS[tid].top();
314            target = TheISA::buildRetPC(instPC, rasTop);
315
316            // Record the top entry of the RAS, and its index.
317            predict_record.usedRAS = true;
318            predict_record.RASIndex = RAS[tid].topIdx();
319            predict_record.RASTarget = rasTop;
320
321            assert(predict_record.RASIndex < 16);
322
323            RAS[tid].pop();
324
325            DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
326                    "RAS predicted target: %s, RAS index: %i.\n",
327                    tid, instPC, target,
328                    predict_record.RASIndex);
329        } else {
330            ++BTBLookups;
331
332            if (inst->isCall()) {
333
334                RAS[tid].push(instPC);
335                predict_record.pushedRAS = true;
336
337                // Record that it was a call so that the top RAS entry can
338                // be popped off if the speculation is incorrect.
339                predict_record.wasCall = true;
340
341                DPRINTF(Branch, "[tid:%i]: Instruction %s was a call"
342                        ", adding %s to the RAS index: %i.\n",
343                        tid, instPC, predPC,
344                        RAS[tid].topIdx());
345            }
346
347            if (inst->isCall() &&
348                inst->isUncondCtrl() &&
349                inst->isDirectCtrl()) {
350                target = inst->branchTarget(instPC);
351            } else if (BTB.valid(predPC.instAddr(), asid)) {
352                ++BTBHits;
353
354                // If it's not a return, use the BTB to get the target addr.
355                target = BTB.lookup(predPC.instAddr(), asid);
356
357                DPRINTF(Branch, "[tid:%i]: [asid:%i] Instruction %s "
358                        "predicted target is %s.\n",
359                        tid, asid, instPC, target);
360            } else {
361                DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
362                        "valid entry, predicting false.\n",tid);
363                pred_taken = false;
364            }
365        }
366    }
367
368    if (pred_taken) {
369        // Set the PC and the instruction's predicted target.
370        predPC = target;
371    }
372    DPRINTF(Branch, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
373            tid, seqNum, predPC);
374
375    predHist[tid].push_front(predict_record);
376
377    DPRINTF(Branch, "[tid:%i] [sn:%i] pushed onto front of predHist "
378            "...predHist.size(): %i\n",
379            tid, seqNum, predHist[tid].size());
380
381    return pred_taken;
382}
383
384void
385BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
386{
387    DPRINTF(Branch, "[tid:%i]: Committing branches until "
388            "[sn:%lli].\n", tid, done_sn);
389
390    while (!predHist[tid].empty() &&
391           predHist[tid].back().seqNum <= done_sn) {
392        // Update the branch predictor with the correct results.
393        if (!predHist[tid].back().wasSquashed) {
394            update(predHist[tid].back().pc, predHist[tid].back().predTaken,
395                predHist[tid].back().bpHistory, false);
396        } else {
397            retireSquashed(predHist[tid].back().bpHistory);
398        }
399
400        predHist[tid].pop_back();
401    }
402}
403
404void
405BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
406{
407    History &pred_hist = predHist[tid];
408
409    while (!pred_hist.empty() &&
410           pred_hist.front().seqNum > squashed_sn) {
411        if (pred_hist.front().usedRAS) {
412            DPRINTF(Branch, "[tid:%i]: Restoring top of RAS to: %i,"
413                    " target: %s.\n", tid,
414                    pred_hist.front().RASIndex, pred_hist.front().RASTarget);
415
416            RAS[tid].restore(pred_hist.front().RASIndex,
417                             pred_hist.front().RASTarget);
418        } else if(pred_hist.front().wasCall && pred_hist.front().pushedRAS) {
419             // Was a call but predicated false. Pop RAS here
420             DPRINTF(Branch, "[tid: %i] Squashing"
421                     "  Call [sn:%i] PC: %s Popping RAS\n", tid,
422                     pred_hist.front().seqNum, pred_hist.front().pc);
423             RAS[tid].pop();
424        }
425
426        // This call should delete the bpHistory.
427        squash(pred_hist.front().bpHistory);
428
429        DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
430                "PC %s.\n", tid, pred_hist.front().seqNum,
431                pred_hist.front().pc);
432
433        pred_hist.pop_front();
434
435        DPRINTF(Branch, "[tid:%i]: predHist.size(): %i\n",
436                tid, predHist[tid].size());
437    }
438}
439
440void
441BPredUnit::squash(const InstSeqNum &squashed_sn,
442                  const TheISA::PCState &corrTarget,
443                  bool actually_taken, ThreadID tid)
444{
445    // Now that we know that a branch was mispredicted, we need to undo
446    // all the branches that have been seen up until this branch and
447    // fix up everything.
448    // NOTE: This should be call conceivably in 2 scenarios:
449    // (1) After an branch is executed, it updates its status in the ROB
450    //     The commit stage then checks the ROB update and sends a signal to
451    //     the fetch stage to squash history after the mispredict
452    // (2) In the decode stage, you can find out early if a unconditional
453    //     PC-relative, branch was predicted incorrectly. If so, a signal
454    //     to the fetch stage is sent to squash history after the mispredict
455
456    History &pred_hist = predHist[tid];
457
458    ++condIncorrect;
459    ppMisses->notify(1);
460
461    DPRINTF(Branch, "[tid:%i]: Squashing from sequence number %i, "
462            "setting target to %s.\n", tid, squashed_sn, corrTarget);
463
464    // Squash All Branches AFTER this mispredicted branch
465    squash(squashed_sn, tid);
466
467    // If there's a squash due to a syscall, there may not be an entry
468    // corresponding to the squash.  In that case, don't bother trying to
469    // fix up the entry.
470    if (!pred_hist.empty()) {
471
472        auto hist_it = pred_hist.begin();
473        //HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
474        //                       squashed_sn);
475
476        //assert(hist_it != pred_hist.end());
477        if (pred_hist.front().seqNum != squashed_sn) {
478            DPRINTF(Branch, "Front sn %i != Squash sn %i\n",
479                    pred_hist.front().seqNum, squashed_sn);
480
481            assert(pred_hist.front().seqNum == squashed_sn);
482        }
483
484
485        if ((*hist_it).usedRAS) {
486            ++RASIncorrect;
487        }
488
489        update((*hist_it).pc, actually_taken,
490               pred_hist.front().bpHistory, true);
491        hist_it->wasSquashed = true;
492
493        if (actually_taken) {
494            if (hist_it->wasReturn && !hist_it->usedRAS) {
495                 DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
496                         "  return [sn:%i] PC: %s\n", tid, hist_it->seqNum,
497                         hist_it->pc);
498                 RAS[tid].pop();
499                 hist_it->usedRAS = true;
500            }
501
502            DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
503                    " PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
504
505            BTB.update((*hist_it).pc, corrTarget, tid);
506
507        } else {
508           //Actually not Taken
509           if (hist_it->usedRAS) {
510                DPRINTF(Branch,"[tid: %i] Incorrectly predicted"
511                        "  return [sn:%i] PC: %s Restoring RAS\n", tid,
512                        hist_it->seqNum, hist_it->pc);
513                DPRINTF(Branch, "[tid:%i]: Restoring top of RAS"
514                        " to: %i, target: %s.\n", tid,
515                        hist_it->RASIndex, hist_it->RASTarget);
516                RAS[tid].restore(hist_it->RASIndex, hist_it->RASTarget);
517                hist_it->usedRAS = false;
518           } else if (hist_it->wasCall && hist_it->pushedRAS) {
519                 //Was a Call but predicated false. Pop RAS here
520                 DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
521                         "  Call [sn:%i] PC: %s Popping RAS\n", tid,
522                         hist_it->seqNum, hist_it->pc);
523                 RAS[tid].pop();
524                 hist_it->pushedRAS = false;
525           }
526        }
527    } else {
528        DPRINTF(Branch, "[tid:%i]: [sn:%i] pred_hist empty, can't "
529                "update.\n", tid, squashed_sn);
530    }
531}
532
533void
534BPredUnit::dump()
535{
536    int i = 0;
537    for (const auto& ph : predHist) {
538        if (!ph.empty()) {
539            auto pred_hist_it = ph.begin();
540
541            cprintf("predHist[%i].size(): %i\n", i++, ph.size());
542
543            while (pred_hist_it != ph.end()) {
544                cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
545                        "bpHistory:%#x\n",
546                        pred_hist_it->seqNum, pred_hist_it->pc,
547                        pred_hist_it->tid, pred_hist_it->predTaken,
548                        pred_hist_it->bpHistory);
549                pred_hist_it++;
550            }
551
552            cprintf("\n");
553        }
554    }
555}
556
557