Skip to content

Commit 5850689

Browse files
committed
bpu: add realistic 2-taken paths in ubtb
Change-Id: I875ccc0a59f7fff3103bcc4d31740915237fbcc7
1 parent ca72aff commit 5850689

2 files changed

Lines changed: 339 additions & 35 deletions

File tree

src/cpu/pred/btb/btb_ubtb.cc

Lines changed: 282 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#include "cpu/pred/btb/btb_ubtb.hh"
3131

32+
#include <algorithm>
33+
3234
#include "base/intmath.hh"
3335
#include "base/trace.hh"
3436
#include "common.hh"
@@ -117,6 +119,13 @@ UBTB::fillStagePredictions(const TickedUBTBEntry &entry, std::vector<FullBTBPred
117119
}
118120

119121
if (entry.valid) {
122+
for (int i = 0; i < entry.numNTConds; i++) {
123+
auto dummy = BTBEntry();
124+
dummy.valid = true;
125+
dummy.isCond = true;
126+
dummy.pc = 0xdeadbeef;
127+
FillStageLoop(s) stagePreds[s].btbEntries.push_back(dummy);
128+
}
120129
FillStageLoop(s) stagePreds[s].btbEntries.push_back(BTBEntry(entry));
121130
if (entry.isCond) {
122131
// the always taken field of BTBEntry is ignored in uBTB
@@ -133,53 +142,130 @@ UBTB::fillStagePredictions(const TickedUBTBEntry &entry, std::vector<FullBTBPred
133142
}
134143
}
135144

145+
void
146+
UBTB::fillSecondPrediction(const BranchInfo &branchInfo,
147+
Addr bbStart,
148+
FullBTBPrediction &prediction)
149+
{
150+
prediction.btbEntries.clear();
151+
prediction.condTakens.clear();
152+
prediction.indirectTargets.clear();
153+
prediction.bbStart = bbStart;
154+
prediction.predTick = curTick();
155+
prediction.predSource = 0;
156+
157+
BTBEntry entry(branchInfo);
158+
prediction.btbEntries.push_back(entry);
159+
if (entry.isCond && entry.alwaysTaken) {
160+
prediction.condTakens.push_back({entry.pc, true});
161+
}
162+
if (entry.isIndirect) {
163+
prediction.indirectTargets.push_back({entry.pc, entry.target});
164+
if (entry.isReturn) {
165+
prediction.returnTarget = entry.target;
166+
}
167+
}
168+
}
169+
170+
void
171+
UBTB::fillSecondPredictionFallthrough(Addr secondFBStart,
172+
FullBTBPrediction &prediction)
173+
{
174+
prediction.btbEntries.clear();
175+
prediction.condTakens.clear();
176+
prediction.indirectTargets.clear();
177+
prediction.bbStart = secondFBStart;
178+
prediction.predTick = curTick();
179+
prediction.predSource = 0;
180+
}
181+
136182
void
137183
UBTB::putPCHistory(Addr startAddr, const boost::dynamic_bitset<> &history, std::vector<FullBTBPrediction> &stagePreds)
138184
{
139185
meta = std::make_shared<UBTBMeta>();
140-
auto it = lookup(startAddr);
186+
int hit_index = lookup(startAddr);
141187
auto& entry = meta->hit_entry;
142-
entry = (it != ubtb.end()) ? *it : TickedUBTBEntry();
188+
entry = (hit_index >= 0) ? ubtb[hit_index] : TickedUBTBEntry();
143189

144190
PredStatistics(entry, startAddr);
145191

146192
// Fill predictions for each pipeline stage
147193
fillStagePredictions(entry, stagePreds);
148194

149195
// Update metadata for later stages
150-
lastPred.hit_entry = it;
196+
lastPred.hit_index = hit_index;
197+
}
198+
199+
std::pair<int, bool>
200+
UBTB::putPCHistory2Taken(Addr startAddr,
201+
const boost::dynamic_bitset<> &history,
202+
std::vector<FullBTBPrediction> &stagePreds,
203+
FullBTBPrediction &secondPrediction)
204+
{
205+
meta = std::make_shared<UBTBMeta>();
206+
int hit_index = lookup(startAddr);
207+
auto &entry = meta->hit_entry;
208+
entry = (hit_index >= 0) ? ubtb[hit_index] : TickedUBTBEntry();
209+
210+
PredStatistics(entry, startAddr);
211+
fillStagePredictions(entry, stagePreds);
212+
lastPred.hit_index = hit_index;
213+
214+
bool has_second_prediction = false;
215+
secondPrediction.btbEntries.clear();
216+
secondPrediction.condTakens.clear();
217+
secondPrediction.indirectTargets.clear();
218+
219+
if (entry.valid && entry.valid_2nd) {
220+
Addr second_bb_start = stagePreds[0].getTarget(predictWidth);
221+
if (entry.pt_2nd) {
222+
fillSecondPrediction(entry.branch_info_2nd, second_bb_start, secondPrediction);
223+
if (!secondPrediction.btbEntries.empty()) {
224+
Addr control_addr = secondPrediction.getTakenEntry().pc;
225+
Addr fall_through = secondPrediction.getFallThrough(predictWidth);
226+
if (control_addr >= second_bb_start && control_addr < fall_through) {
227+
has_second_prediction = true;
228+
ubtbStats.twoTakenPredTaken++;
229+
} else {
230+
ubtbStats.twoTakenPredRangeFailed++;
231+
secondPrediction.btbEntries.clear();
232+
}
233+
}
234+
} else {
235+
fillSecondPredictionFallthrough(second_bb_start, secondPrediction);
236+
has_second_prediction = true;
237+
ubtbStats.twoTakenPredFallThrough++;
238+
}
239+
}
240+
241+
return std::make_pair(hit_index, has_second_prediction);
151242
}
152243

153-
UBTB::UBTBIter
244+
int
154245
UBTB::lookup(Addr startAddr)
155246
{
156247
if (startAddr & 0x1) {
157-
return ubtb.end(); // ignore false hit when lowest bit is 1
248+
return -1;
158249
}
159250

160251
Addr current_tag = getTag(startAddr);
161252

162253
DPRINTF(UBTB, "UBTB: Doing tag comparison for tag %#lx\n", current_tag);
163254

164-
auto it = std::find_if(ubtb.begin(), ubtb.end(),
165-
[current_tag](const TickedUBTBEntry &way) { return way.valid && way.tag == current_tag; });
166-
167-
if (it != ubtb.end()) {
168-
// Found a hit - verify no duplicates
169-
auto duplicate = std::find_if(std::next(it), ubtb.end(), [current_tag](const TickedUBTBEntry &way) {
170-
return way.valid && way.tag == current_tag;
171-
});
172-
if (duplicate != ubtb.end()) {
173-
DPRINTF(UBTB, "UBTB: Multiple hits found in uBTB for the same tag %#lx\n", current_tag);
174-
duplicate->valid = false; // invalidate the duplicate entry
255+
for (size_t i = 0; i < ubtb.size(); ++i) {
256+
if (!ubtb[i].valid || ubtb[i].tag != current_tag) {
257+
continue;
258+
}
259+
for (size_t j = i + 1; j < ubtb.size(); ++j) {
260+
if (ubtb[j].valid && ubtb[j].tag == current_tag) {
261+
ubtb[j].valid = false;
262+
}
175263
}
176-
// go on to update the mruList
177-
it->tick = curTick(); // Update timestamp for MRU
178-
// might be unnecessary, considering the heap is updated on every reaplacement
264+
ubtb[i].tick = curTick();
179265
std::make_heap(mruList.begin(), mruList.end(), older());
266+
return static_cast<int>(i);
180267
}
181-
182-
return it;
268+
return -1;
183269
}
184270

185271

@@ -204,17 +290,175 @@ UBTB::updateUsingS3Pred(FullBTBPrediction &s3Pred)
204290
return;
205291
}
206292

293+
train1Taken(s3Pred);
294+
}
295+
296+
int
297+
UBTB::calculateNumNTConds(FullBTBPrediction& prediction)
298+
{
299+
int numNTConds = prediction.getHistInfo().first;
300+
if (prediction.getTakenEntry().isCond) {
301+
numNTConds--;
302+
}
303+
return std::max(0, numNTConds);
304+
}
305+
306+
bool
307+
UBTB::shouldSetPtSecond(const FullBTBPrediction& secondPred)
308+
{
309+
return !secondPred.btbEntries.empty();
310+
}
311+
312+
void
313+
UBTB::replaceEntry(int entryIndex, FullBTBPrediction &newPrediction)
314+
{
315+
assert(entryIndex >= 0 && entryIndex < static_cast<int>(ubtb.size()));
316+
auto taken = newPrediction.getTakenEntry();
317+
assert(taken.valid);
318+
TickedUBTBEntry newEntry(taken, curTick());
319+
newEntry.target = newPrediction.getTarget(predictWidth);
320+
newEntry.tag = getTag(newPrediction.bbStart);
321+
newEntry.numNTConds = calculateNumNTConds(newPrediction);
322+
ubtb[entryIndex] = newEntry;
323+
}
324+
325+
void
326+
UBTB::addSecondPredictionToEntry(int entryIndex,
327+
FullBTBPrediction* secondPred)
328+
{
329+
if (!secondPred) {
330+
return;
331+
}
332+
assert(entryIndex >= 0 && entryIndex < static_cast<int>(ubtb.size()));
333+
auto &entry = ubtb[entryIndex];
334+
if (!entry.valid) {
335+
return;
336+
}
337+
entry.valid_2nd = true;
338+
entry.pt_2nd = shouldSetPtSecond(*secondPred);
339+
if (entry.pt_2nd) {
340+
auto second_taken = secondPred->getTakenEntry();
341+
if (!second_taken.valid) {
342+
entry.valid_2nd = false;
343+
return;
344+
}
345+
entry.branch_info_2nd = second_taken;
346+
entry.branch_info_2nd.target = secondPred->getTarget(predictWidth);
347+
} else {
348+
entry.branch_info_2nd = BranchInfo();
349+
}
350+
}
351+
352+
bool
353+
UBTB::check2TakenConditions(FullBTBPrediction& dff,
354+
const FullBTBPrediction& s3Pred)
355+
{
356+
ubtbStats.twoTakenConditionChecks++;
357+
if (dff.btbEntries.empty()) {
358+
ubtbStats.twoTakenFailEmptyPreds++;
359+
return false;
360+
}
361+
if (!dff.isTaken()) {
362+
ubtbStats.twoTakenFailFirstNotTaken++;
363+
return false;
364+
}
365+
if (s3Pred.btbEntries.empty()) {
366+
ubtbStats.twoTakenAcceptFallthrough++;
367+
return true;
368+
}
369+
auto second = s3Pred.btbEntries[0];
370+
if (second.isIndirect) {
371+
ubtbStats.twoTakenFailSecondIndirect++;
372+
return false;
373+
}
374+
if (second.isCond && !second.alwaysTaken) {
375+
ubtbStats.twoTakenFailSecondCond++;
376+
return false;
377+
}
378+
if (second.isCond && second.alwaysTaken) {
379+
ubtbStats.twoTakenAcceptAlwaysTaken++;
380+
return true;
381+
}
382+
ubtbStats.twoTakenAcceptOther++;
383+
return true;
384+
}
385+
386+
void
387+
UBTB::trainCommon(int entry_index,
388+
FullBTBPrediction& pred,
389+
FullBTBPrediction* secondPred)
390+
{
391+
auto s3TakenEntry = pred.getTakenEntry();
392+
393+
if (entry_index >= 0) {
394+
auto &entry = ubtb[entry_index];
395+
if (!s3TakenEntry.valid) {
396+
updateUCtr(entry.uctr, false);
397+
if (entry.uctr == 0) {
398+
entry.valid = false;
399+
entry.valid_2nd = false;
400+
}
401+
return;
402+
}
403+
if (entry.pc != s3TakenEntry.pc ||
404+
entry.target != pred.getTarget(predictWidth) ||
405+
entry.numNTConds != calculateNumNTConds(pred)) {
406+
updateUCtr(entry.uctr, false);
407+
if (entry.uctr == 0) {
408+
replaceEntry(entry_index, pred);
409+
addSecondPredictionToEntry(entry_index, secondPred);
410+
}
411+
} else {
412+
updateUCtr(entry.uctr, true);
413+
addSecondPredictionToEntry(entry_index, secondPred);
414+
}
415+
return;
416+
}
417+
418+
if (!s3TakenEntry.valid) {
419+
return;
420+
}
421+
int toBeReplacedIndex = -1;
422+
for (size_t i = 0; i < ubtb.size(); ++i) {
423+
if (!ubtb[i].valid) {
424+
toBeReplacedIndex = static_cast<int>(i);
425+
break;
426+
}
427+
}
428+
if (toBeReplacedIndex == -1) {
429+
std::make_heap(mruList.begin(), mruList.end(), older());
430+
toBeReplacedIndex = static_cast<int>(mruList.front() - ubtb.begin());
431+
}
432+
replaceEntry(toBeReplacedIndex, pred);
433+
addSecondPredictionToEntry(toBeReplacedIndex, secondPred);
434+
}
435+
436+
void
437+
UBTB::train1Taken(FullBTBPrediction &s3Pred)
438+
{
207439
auto takenEntry = s3Pred.getTakenEntry();
208440
if (takenEntry.valid) {
209441
ubtbStats.s3UpdateHits++;
210-
}else {
442+
} else {
211443
ubtbStats.s3UpdateMisses++;
212444
}
213-
auto startAddr = s3Pred.bbStart;
214-
UBTBIter oldEntryIter = lastPred.hit_entry;
215-
takenEntry.source = getComponentIdx();
216-
updateNewEntry(oldEntryIter, takenEntry, startAddr);
445+
trainCommon(lastPred.hit_index, s3Pred, nullptr);
446+
}
217447

448+
void
449+
UBTB::train2Taken(FullBTBPrediction &dffPred,
450+
FullBTBPrediction &s3Pred,
451+
int hitIndex)
452+
{
453+
if (dffPred.getTarget(predictWidth) != s3Pred.bbStart) {
454+
trainCommon(hitIndex, dffPred, nullptr);
455+
return;
456+
}
457+
if (!check2TakenConditions(dffPred, s3Pred)) {
458+
trainCommon(hitIndex, dffPred, nullptr);
459+
return;
460+
}
461+
trainCommon(hitIndex, dffPred, &s3Pred);
218462
}
219463

220464

@@ -463,7 +707,18 @@ UBTB::UBTBStats::UBTBStats(statistics::Group *parent)
463707
ADD_STAT(s1Misses3Taken, statistics::units::Count::get(), "s1 misses s3 predicted taken"),
464708
ADD_STAT(s1Hits3Taken, statistics::units::Count::get(), "s1 hits s3 predicted taken"),
465709
ADD_STAT(s1Misses3FallThrough, statistics::units::Count::get(), "s1 misses s3 predicted fall through"),
466-
ADD_STAT(s1InvalidatedEntries, statistics::units::Count::get(), "s1 invalidated entries")
710+
ADD_STAT(s1InvalidatedEntries, statistics::units::Count::get(), "s1 invalidated entries"),
711+
ADD_STAT(twoTakenConditionChecks, statistics::units::Count::get(), "2taken condition checks"),
712+
ADD_STAT(twoTakenFailEmptyPreds, statistics::units::Count::get(), "2taken reject empty preds"),
713+
ADD_STAT(twoTakenFailFirstNotTaken, statistics::units::Count::get(), "2taken reject first not taken"),
714+
ADD_STAT(twoTakenFailSecondIndirect, statistics::units::Count::get(), "2taken reject second indirect"),
715+
ADD_STAT(twoTakenFailSecondCond, statistics::units::Count::get(), "2taken reject non-always cond second"),
716+
ADD_STAT(twoTakenAcceptAlwaysTaken, statistics::units::Count::get(), "2taken accept always-taken cond second"),
717+
ADD_STAT(twoTakenAcceptFallthrough, statistics::units::Count::get(), "2taken accept second fallthrough"),
718+
ADD_STAT(twoTakenAcceptOther, statistics::units::Count::get(), "2taken accept other second type"),
719+
ADD_STAT(twoTakenPredTaken, statistics::units::Count::get(), "2taken predicted second taken"),
720+
ADD_STAT(twoTakenPredFallThrough, statistics::units::Count::get(), "2taken predicted second fallthrough"),
721+
ADD_STAT(twoTakenPredRangeFailed, statistics::units::Count::get(), "2taken second range check failed")
467722
{
468723
}
469724

0 commit comments

Comments
 (0)