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+
136182void
137183UBTB::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
154245UBTB::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