gem5 v24.1.0.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
loop_predictor.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022-2023 The University of Edinburgh
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2014 The University of Wisconsin
15 *
16 * Copyright (c) 2006 INRIA (Institut National de Recherche en
17 * Informatique et en Automatique / French National Research Institute
18 * for Computer Science and Applied Mathematics)
19 *
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are
24 * met: redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer;
26 * redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution;
29 * neither the name of the copyright holders nor the names of its
30 * contributors may be used to endorse or promote products derived from
31 * this software without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
36 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
40 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
41 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45
47
48#include "base/trace.hh"
49#include "debug/LTage.hh"
50#include "params/LoopPredictor.hh"
51
52namespace gem5
53{
54
55namespace branch_prediction
56{
57
58LoopPredictor::LoopPredictor(const LoopPredictorParams &p)
59 : SimObject(p), logSizeLoopPred(p.logSizeLoopPred),
60 loopTableAgeBits(p.loopTableAgeBits),
61 loopTableConfidenceBits(p.loopTableConfidenceBits),
62 loopTableTagBits(p.loopTableTagBits),
63 loopTableIterBits(p.loopTableIterBits),
64 logLoopTableAssoc(p.logLoopTableAssoc),
65 confidenceThreshold((1 << loopTableConfidenceBits) - 1),
66 loopTagMask((1 << loopTableTagBits) - 1),
67 loopNumIterMask((1 << loopTableIterBits) - 1),
68 loopSetMask((1 << (logSizeLoopPred - logLoopTableAssoc)) - 1),
69 loopUseCounter(-1),
70 withLoopBits(p.withLoopBits),
71 useDirectionBit(p.useDirectionBit),
72 useSpeculation(p.useSpeculation),
73 useHashing(p.useHashing),
74 restrictAllocation(p.restrictAllocation),
75 initialLoopIter(p.initialLoopIter),
76 initialLoopAge(p.initialLoopAge),
77 optionalAgeReset(p.optionalAgeReset),
78 stats(this)
79{
80 assert(initialLoopAge <= ((1 << loopTableAgeBits) - 1));
81}
82
83void
85{
86 // we use uint16_t type for these vales, so they cannot be more than
87 // 16 bits
88 assert(loopTableTagBits <= 16);
89 assert(loopTableIterBits <= 16);
90
92
93 ltable = new LoopEntry[1ULL << logSizeLoopPred];
94}
95
98{
99 return new BranchInfo();
100}
101
102int
103LoopPredictor::lindex(Addr pc_in, unsigned instShiftAmt) const
104{
105 // The loop table is implemented as a linear table
106 // If associativity is N (N being 1 << logLoopTableAssoc),
107 // the first N entries are for set 0, the next N entries are for set 1,
108 // and so on.
109 // Thus, this function calculates the set and then it gets left shifted
110 // by logLoopTableAssoc in order to return the index of the first of the
111 // N entries of the set
112 Addr pc = pc_in >> instShiftAmt;
113 if (useHashing) {
114 pc ^= pc_in;
115 }
116 return ((pc & loopSetMask) << logLoopTableAssoc);
117}
118
119int
120LoopPredictor::finallindex(int index, int lowPcBits, int way) const
121{
122 return (useHashing ? (index ^ ((lowPcBits >> way) << logLoopTableAssoc)) :
123 (index))
124 + way;
125}
126
127//loop prediction: only used if high confidence
128bool
130 unsigned instShiftAmt) const
131{
132 bi->loopHit = -1;
133 bi->loopPredValid = false;
134 bi->loopIndex = lindex(pc, instShiftAmt);
135
136 if (useHashing) {
137 unsigned pcShift = logSizeLoopPred - logLoopTableAssoc;
138 bi->loopIndexB = (pc >> pcShift) & loopSetMask;
139 bi->loopTag = (pc >> pcShift) ^ (pc >> (pcShift + loopTableTagBits));
140 bi->loopTag &= loopTagMask;
141 } else {
142 unsigned pcShift = instShiftAmt + logSizeLoopPred - logLoopTableAssoc;
143 bi->loopTag = (pc >> pcShift) & loopTagMask;
144 // bi->loopIndexB is not used without hash
145 }
146
147 for (int i = 0; i < (1 << logLoopTableAssoc); i++) {
148 int idx = finallindex(bi->loopIndex, bi->loopIndexB, i);
149 if (ltable[idx].tag == bi->loopTag) {
150 bi->loopHit = i;
151 bi->loopPredValid = calcConf(idx);
152
153 uint16_t iter = speculative ? ltable[idx].currentIterSpec
154 : ltable[idx].currentIter;
155
156 if ((iter + 1) == ltable[idx].numIter) {
157 return useDirectionBit ? !(ltable[idx].dir) : false;
158 } else {
159 return useDirectionBit ? (ltable[idx].dir) : true;
160 }
161 }
162 }
163 return false;
164}
165
166bool
171
172void
174{
175 if (bi->loopHit>=0) {
176 int index = finallindex(bi->loopIndex, bi->loopIndexB, bi->loopHit);
177 if (taken != ltable[index].dir) {
179 } else {
182 }
183 }
184}
185
186bool
188{
189 return false;
190}
191
192void
193LoopPredictor::loopUpdate(Addr pc, bool taken, BranchInfo* bi, bool tage_pred)
194{
195 int idx = finallindex(bi->loopIndex, bi->loopIndexB, bi->loopHit);
196 if (bi->loopHit >= 0) {
197 //already a hit
198 if (bi->loopPredValid) {
199 if (taken != bi->loopPred) {
200 // free the entry
201 ltable[idx].numIter = 0;
202 ltable[idx].age = 0;
203 ltable[idx].confidence = 0;
204 ltable[idx].currentIter = 0;
205 return;
206 } else if (bi->loopPred != tage_pred || optionalAgeInc()) {
207 DPRINTF(LTage, "Loop Prediction success:%lx\n",pc);
209 }
210 }
211
212 ltable[idx].currentIter =
214 if (ltable[idx].currentIter > ltable[idx].numIter) {
215 ltable[idx].confidence = 0;
216 if (ltable[idx].numIter != 0) {
217 // free the entry
218 ltable[idx].numIter = 0;
219 if (optionalAgeReset) {
220 ltable[idx].age = 0;
221 }
222 }
223 }
224
225 if (taken != (useDirectionBit ? ltable[idx].dir : true)) {
226 if (ltable[idx].currentIter == ltable[idx].numIter) {
227 DPRINTF(LTage, "Loop End predicted successfully:%lx\n", pc);
228 unsignedCtrUpdate(ltable[idx].confidence, true,
230 //just do not predict when the loop count is 1 or 2
231 if (ltable[idx].numIter < 3) {
232 // free the entry
233 ltable[idx].dir = taken; // ignored if no useDirectionBit
234 ltable[idx].numIter = 0;
235 ltable[idx].age = 0;
236 ltable[idx].confidence = 0;
237 }
238 } else {
239 DPRINTF(LTage, "Loop End predicted incorrectly:%lx\n", pc);
240 if (ltable[idx].numIter == 0) {
241 // first complete nest;
242 ltable[idx].confidence = 0;
243 ltable[idx].numIter = ltable[idx].currentIter;
244 } else {
245 //not the same number of iterations as last time: free the
246 //entry
247 ltable[idx].numIter = 0;
248 if (optionalAgeReset) {
249 ltable[idx].age = 0;
250 }
251 ltable[idx].confidence = 0;
252 }
253 }
254 ltable[idx].currentIter = 0;
255 }
256
257 } else if (useDirectionBit ? (bi->predTaken != taken) : taken) {
258 if ((rng->random<int>() & 3) == 0 || !restrictAllocation) {
259 //try to allocate an entry on taken branch
260 int nrand = rng->random<int>();
261 for (int i = 0; i < (1 << logLoopTableAssoc); i++) {
262 int loop_hit = (nrand + i) & ((1 << logLoopTableAssoc) - 1);
263 idx = finallindex(bi->loopIndex, bi->loopIndexB, loop_hit);
264 if (ltable[idx].age == 0) {
265 DPRINTF(LTage,
266 "Allocating loop pred entry for branch %lx\n",
267 pc);
268 ltable[idx].dir = !taken; // ignored if no useDirectionBit
269 ltable[idx].tag = bi->loopTag;
270 ltable[idx].numIter = 0;
272 ltable[idx].confidence = 0;
274 break;
275
276 } else {
277 ltable[idx].age--;
278 }
279 if (restrictAllocation) {
280 break;
281 }
282 }
283 }
284 }
285}
286
287bool
288LoopPredictor::loopPredict(ThreadID tid, Addr branch_pc, bool cond_branch,
289 BranchInfo* bi, bool prev_pred_taken, unsigned instShiftAmt)
290{
291 bool pred_taken = prev_pred_taken;
292 if (cond_branch) {
293 // loop prediction
294 bi->loopPred = getLoop(branch_pc, bi, useSpeculation, instShiftAmt);
295
296 if ((loopUseCounter >= 0) && bi->loopPredValid) {
297 pred_taken = bi->loopPred;
298 bi->loopPredUsed = true;
299 }
300
301 if (useSpeculation) {
302 specLoopUpdate(pred_taken, bi);
303 }
304 }
305
306 return pred_taken;
307}
308
309void
311{
312 if (bi->loopHit >= 0) {
313 int idx = finallindex(bi->loopIndex,
314 bi->loopIndexB,
315 bi->loopHit);
316 ltable[idx].currentIterSpec = bi->currentIter;
317 }
318}
319
320void
322{
323 if (bi->loopHit >= 0) {
324 int idx = finallindex(bi->loopIndex,
325 bi->loopIndexB,
326 bi->loopHit);
327 ltable[idx].currentIterSpec = bi->currentIter;
328 }
329}
330
331void
333{
334 if (bi->loopPredUsed) {
335 stats.used++;
336 if (taken == bi->loopPred) {
337 stats.correct++;
338 } else {
339 stats.wrong++;
340 }
341 }
342}
343
344void
346 bool tage_pred, BranchInfo* bi,
347 unsigned instShiftAmt)
348{
349 if (useSpeculation) {
350 // recalculate loop prediction without speculation
351 // It is ok to overwrite the loop prediction fields in bi
352 // as the stats have already been updated with the previous
353 // values
354 bi->loopPred = getLoop(branch_pc, bi, false, instShiftAmt);
355 }
356
357 if (bi->loopPredValid) {
358 if (bi->predTaken != bi->loopPred) {
360 (bi->loopPred == taken),
362 }
363 }
364
365 loopUpdate(branch_pc, taken, bi, tage_pred);
366}
367
369 statistics::Group *parent)
370 : statistics::Group(parent),
371 ADD_STAT(used, statistics::units::Count::get(),
372 "Number of times the loop predictor is the provider."),
373 ADD_STAT(correct, statistics::units::Count::get(),
374 "Number of times the loop predictor is the provider and the "
375 "prediction is correct"),
376 ADD_STAT(wrong, statistics::units::Count::get(),
377 "Number of times the loop predictor is the provider and the "
378 "prediction is wrong")
379{
380}
381
382size_t
390
391} // namespace branch_prediction
392} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
Abstract superclass for simulation objects.
LoopPredictor(const LoopPredictorParams &p)
void updateStats(bool taken, BranchInfo *bi)
Update the stats.
int finallindex(int lindex, int lowPcBits, int way) const
Computes the index used to access the ltable structures.
static void unsignedCtrUpdate(uint8_t &ctr, bool up, unsigned nbits)
Updates an unsigned counter based on up/down parameter.
static void signedCtrUpdate(int8_t &ctr, bool up, unsigned nbits)
void specLoopUpdate(bool taken, BranchInfo *bi)
Speculatively updates the loop predictor iteration count (only for useSpeculation).
gem5::branch_prediction::LoopPredictor::LoopPredictorStats stats
int lindex(Addr pc_in, unsigned instShiftAmt) const
Computes the index used to access the loop predictor.
void init() override
Initialize the loop predictor.
void condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken, bool tage_pred, BranchInfo *bi, unsigned instShiftAmt)
Update LTAGE for conditional branches.
virtual bool calcConf(int index) const
bool getLoop(Addr pc, BranchInfo *bi, bool speculative, unsigned instShiftAmt) const
Get a branch prediction from the loop predictor.
bool loopPredict(ThreadID tid, Addr branch_pc, bool cond_branch, BranchInfo *bi, bool prev_pred_taken, unsigned instShiftAmt)
Get the loop prediction.
void loopUpdate(Addr pc, bool Taken, BranchInfo *bi, bool tage_pred)
Updates the loop predictor.
void squash(ThreadID tid, BranchInfo *bi)
Statistics container.
Definition group.hh:93
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 4 > pc
Bitfield< 30, 0 > index
Bitfield< 0 > p
Bitfield< 20, 16 > bi
Definition types.hh:80
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
int16_t ThreadID
Thread index/ID type.
Definition types.hh:235
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147

Generated on Mon Jan 13 2025 04:28:32 for gem5 by doxygen 1.9.8