gem5 v24.0.0.0
Loading...
Searching...
No Matches
simple_indirect.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 ARM Limited
3 * Copyright (c) 2022-2023 The University of Edinburgh
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
17 * met: redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer;
19 * redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution;
22 * neither the name of the copyright holders nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
40
41#include "base/intmath.hh"
42#include "debug/Indirect.hh"
43
44namespace gem5
45{
46
47namespace branch_prediction
48{
49
51 const SimpleIndirectPredictorParams &params)
52 : IndirectPredictor(params),
53 hashGHR(params.indirectHashGHR),
54 hashTargets(params.indirectHashTargets),
55 numSets(params.indirectSets),
56 numWays(params.indirectWays),
57 tagBits(params.indirectTagSize),
58 pathLength(params.indirectPathLength),
59 speculativePathLength(params.speculativePathLength),
60 instShift(params.instShiftAmt),
61 ghrNumBits(params.indirectGHRBits),
62 ghrMask((1 << params.indirectGHRBits)-1),
63 stats(this)
64{
65 if (!isPowerOf2(numSets)) {
66 panic("Indirect predictor requires power of 2 number of sets");
67 }
68
69 threadInfo.resize(params.numThreads);
70
71 targetCache.resize(numSets);
72 for (unsigned i = 0; i < numSets; i++) {
73 targetCache[i].resize(numWays);
74 }
75
76 fatal_if(ghrNumBits > (sizeof(ThreadInfo::ghr)*8), "ghr_size is too big");
77}
78
79
80void
82{
83 DPRINTF(Indirect, "Reset Indirect predictor\n");
84
85 for (auto& ti : threadInfo) {
86 ti.ghr = 0;
87 ti.pathHist.clear();
88 }
89
90 for (unsigned i = 0; i < numSets; i++) {
91 for (unsigned j = 0; j < numWays; j++) {
92 targetCache[i][j].tag = 0;
93 }
94 }
95}
96
97
98void
100{
101 // Record the GHR as it was before this prediction
102 // It will be used to recover the history in case this prediction is
103 // wrong or belongs to bad path
104 IndirectHistory* history = new IndirectHistory;
105 history->ghr = threadInfo[tid].ghr;
106 i_history = static_cast<void*>(history);
107}
108
109void
111 Addr pc, Addr target)
112{
113 // Direction history
114 threadInfo[tid].ghr <<= 1;
115 threadInfo[tid].ghr |= taken;
116 threadInfo[tid].ghr &= ghrMask;
117}
118
119
120
121// Interface methods ------------------------------
122const PCStateBase *
124 Addr pc, void * &i_history)
125{
126 assert(i_history==nullptr);
127
128 genIndirectInfo(tid, i_history);
129 IndirectHistory *history = static_cast<IndirectHistory*>(i_history);
130
131 history->pcAddr = pc;
132 history->was_indirect = true;
133
135 PCStateBase* target = nullptr;
136 history->hit = lookup(tid, pc, target, history);
137 return target;
138}
139
140bool
142 PCStateBase * &target,
143 IndirectHistory * &history)
144{
145
146 history->set_index = getSetIndex(br_addr, tid);
147 history->tag = getTag(br_addr);
148 assert(history->set_index < numSets);
149 stats.lookups++;
150
151 DPRINTF(Indirect, "Looking up PC:%#x, (set:%d, tag:%d), "
152 "ghr:%#x, pathHist sz:%#x\n",
153 history->pcAddr, history->set_index, history->tag,
154 history->ghr, threadInfo[tid].pathHist.size());
155
156 const auto &iset = targetCache[history->set_index];
157 for (auto way = iset.begin(); way != iset.end(); ++way) {
158 // tag may be 0 and match the default in way->tag, so we also have to
159 // check that way->target has been initialized.
160 if (way->tag == history->tag && way->target) {
161 DPRINTF(Indirect, "Hit %x (target:%s)\n", br_addr, *way->target);
162 set(target, *way->target);
163 history->hit = true;
164 stats.hits++;
165 return history->hit;
166 }
167 }
168 DPRINTF(Indirect, "Miss %x\n", br_addr);
169 history->hit = false;
170 stats.misses++;
171 return history->hit;
172}
173
174
175void
177{
178 if (i_history == nullptr) return;
179 // we do not need to recover the GHR, so delete the information
180 IndirectHistory *history = static_cast<IndirectHistory*>(i_history);
181
182 DPRINTF(Indirect, "Committing seq:%d, PC:%#x, ghr:%#x, pathHist sz:%lu\n",
183 sn, history->pcAddr, history->ghr,
184 threadInfo[tid].pathHist.size());
185
186 delete history;
187 i_history = nullptr;
188
190 while (threadInfo[tid].pathHist.size()
192
193 threadInfo[tid].pathHist.pop_front();
194 }
195}
196
197void
199 bool squash, bool taken, const PCStateBase& target,
200 BranchType br_type, void * &i_history)
201{
202 // If there is no history we did not use the indirect predictor yet.
203 // Create one
204 if (i_history==nullptr) {
205 genIndirectInfo(tid, i_history);
206 }
207 IndirectHistory *history = static_cast<IndirectHistory*>(i_history);
208 assert(history!=nullptr);
209
210 DPRINTF(Indirect, "Update sn:%i PC:%#x, squash:%i, ghr:%#x,path sz:%i\n",
211 sn, pc, squash, history->ghr, threadInfo[tid].pathHist.size());
212
218 history->was_indirect = isIndirectNoReturn(br_type);
219 if (squash) {
220
222 threadInfo[tid].ghr = history->ghr;
223
225 if (history->was_indirect) {
226 if (!threadInfo[tid].pathHist.empty()) {
227 threadInfo[tid].pathHist.pop_back();
228 }
229
230 history->set_index = getSetIndex(history->pcAddr, tid);
231 history->tag = getTag(history->pcAddr);
232
233 DPRINTF(Indirect, "Record Target seq:%d, PC:%#x, TGT:%#x, "
234 "ghr:%#x, (set:%x, tag:%x)\n",
235 sn, history->pcAddr, target, history->ghr,
236 history->set_index, history->tag);
237 }
238 }
239
240 // Only indirect branches are recorded in the path history
241 if (history->was_indirect) {
242
243 DPRINTF(Indirect, "Recording %x seq:%d\n", history->pcAddr, sn);
244 threadInfo[tid].pathHist.emplace_back(
245 history->pcAddr, target.instAddr(), sn);
246
248 }
249
250 // All branches update the global history
251 updateDirectionInfo(tid,taken, history->pcAddr, target.instAddr());
252
253 // Finally if update is called during at squash we know the target
254 // we predicted was wrong therefore we update the target.
255 // We only record the target if the branch was indirect and taken
256 if (squash && history->was_indirect && taken)
257 recordTarget(tid, sn, target, history);
258}
259
260
261
262void
264{
265 if (i_history == nullptr) return;
266
267 // we do not need to recover the GHR, so delete the information
268 IndirectHistory *history = static_cast<IndirectHistory*>(i_history);
269
270 DPRINTF(Indirect, "Squashing seq:%d, PC:%#x, indirect:%i, "
271 "ghr:%#x, pathHist sz:%#x\n",
272 sn, history->pcAddr, history->was_indirect,
273 history->ghr,
274 threadInfo[tid].pathHist.size());
275
276
277 // Revert the global history register.
278 threadInfo[tid].ghr = history->ghr;
279
280 // If we record this branch as indirect branch
281 // remove it from the history.
282 // Restore the old head in the history.
283 if (history->was_indirect) {
284
285 // Should not be empty
286 if (threadInfo[tid].pathHist.size() < pathLength) {
288 }
289
290 if (!threadInfo[tid].pathHist.empty()) {
291 threadInfo[tid].pathHist.pop_back();
292 }
293 }
294
295 delete history;
296 i_history = nullptr;
297}
298
299
300
301
302// Internal functions ------------------------------
303
304
305
306void
308 const PCStateBase& target, IndirectHistory * &history)
309{
310 // Should have just squashed so this branch should be the oldest
311 // and it should be predicted as indirect.
312 assert(!threadInfo[tid].pathHist.empty());
313 assert(history->was_indirect);
314
315 if (threadInfo[tid].pathHist.rbegin()->pcAddr != history->pcAddr) {
316 DPRINTF(Indirect, "History seems to be corrupted. %#x != %#x\n",
317 history->pcAddr,
318 threadInfo[tid].pathHist.rbegin()->pcAddr);
319 }
320
321 DPRINTF(Indirect, "Record Target seq:%d, PC:%#x, TGT:%#x, "
322 "ghr:%#x, (set:%x, tag:%x)\n",
323 sn, history->pcAddr, target.instAddr(), history->ghr,
324 history->set_index, history->tag);
325
326 assert(history->set_index < numSets);
328
329 // Update the target cache
330 auto &iset = targetCache[history->set_index];
331 for (auto way = iset.begin(); way != iset.end(); ++way) {
332 if (way->tag == history->tag) {
333 DPRINTF(Indirect,
334 "Updating Target (seq: %d br:%x set:%d target:%s)\n",
335 sn, history->pcAddr, history->set_index, target);
336 set(way->target, target);
337 return;
338 }
339 }
340
341 DPRINTF(Indirect, "Allocating Target (seq: %d br:%x set:%d target:%s)\n",
342 sn, history->pcAddr, history->set_index, target);
343
344 // Did not find entry, random replacement
345 auto &way = iset[rand() % numWays];
346 way.tag = history->tag;
347 set(way.target, target);
348}
349
350
351
352
353inline Addr
355{
356 Addr hash = br_addr >> instShift;
357 if (hashGHR) {
358 hash ^= threadInfo[tid].ghr;
359 }
360 if (hashTargets) {
361 unsigned hash_shift = floorLog2(numSets) / pathLength;
362 for (int i = threadInfo[tid].pathHist.size()-1, p = 0;
363 i >= 0 && p < pathLength; i--, p++) {
364 hash ^= (threadInfo[tid].pathHist[i].targetAddr >>
365 (instShift + p*hash_shift));
366 }
367 }
368 return hash & (numSets-1);
369}
370
371inline Addr
373{
374 return (br_addr >> instShift) & ((0x1<<tagBits)-1);
375}
376
377
379 statistics::Group *parent)
380 : statistics::Group(parent),
381 ADD_STAT(lookups, statistics::units::Count::get(),
382 "Number of lookups"),
383 ADD_STAT(hits, statistics::units::Count::get(),
384 "Number of hits of a tag"),
385 ADD_STAT(misses, statistics::units::Count::get(),
386 "Number of misses"),
387 ADD_STAT(targetRecords, statistics::units::Count::get(),
388 "Number of targets that where recorded/installed in the cache"),
389 ADD_STAT(indirectRecords, statistics::units::Count::get(),
390 "Number of indirect branches/calls recorded in the"
391 " indirect hist"),
392 ADD_STAT(speculativeOverflows, statistics::units::Count::get(),
393 "Number of times more than the allowed capacity for speculative "
394 "branches/calls where in flight and destroy the path history")
395{
396}
397
398} // namespace branch_prediction
399} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition pcstate.hh:108
void reset() override
Indirect predictor interface.
std::vector< std::vector< IPredEntry > > targetCache
void genIndirectInfo(ThreadID tid, void *&iHistory)
const PCStateBase * lookup(ThreadID tid, InstSeqNum sn, Addr pc, void *&iHistory) override
Predicts the indirect target of an indirect branch.
void recordTarget(ThreadID tid, InstSeqNum sn, const PCStateBase &target, IndirectHistory *&history)
void update(ThreadID tid, InstSeqNum sn, Addr pc, bool squash, bool taken, const PCStateBase &target, BranchType br_type, void *&iHistory) override
Updates the indirect predictor with history information of a branch.
gem5::branch_prediction::SimpleIndirectPredictor::IndirectStats stats
void commit(ThreadID tid, InstSeqNum sn, void *&iHistory) override
A branch gets finally commited.
void squash(ThreadID tid, InstSeqNum sn, void *&iHistory) override
Squashes a branch.
SimpleIndirectPredictor(const SimpleIndirectPredictorParams &params)
void updateDirectionInfo(ThreadID tid, bool taken, Addr pc, Addr target)
Statistics container.
Definition group.hh:93
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
static constexpr std::enable_if_t< std::is_integral_v< T >, int > floorLog2(T x)
Definition intmath.hh:59
static constexpr bool isPowerOf2(const T &n)
Definition intmath.hh:98
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:236
const Params & params() const
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 12, 11 > set
Bitfield< 4 > pc
Bitfield< 0 > p
Bitfield< 30 > ti
enums::BranchType BranchType
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria 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
uint64_t InstSeqNum
Definition inst_seq.hh:40
Indirect branch history information Used for prediction, update and recovery.

Generated on Tue Jun 18 2024 16:24:02 for gem5 by doxygen 1.11.0