Skip to content

Commit 4d9d83b

Browse files
authored
feat(ubtb): remove takenCnt & valid field (#5157)
We only train taken branches into ubtb, if it's not taken, it's not useful. So `usefulCnt` is some sort of `takenCnt`. Therefore, we can remove `takenCnt` and do an always-taken prediction in ubtb. This also allows non-taken branches to be evicted earlier and thus we can use abtb/fallthrough results, so maybe has some performance gain. We can also remove valid as it should always be `usefulCnt != 0`
1 parent 50d1045 commit 4d9d83b

2 files changed

Lines changed: 18 additions & 100 deletions

File tree

‎src/main/scala/xiangshan/frontend/bpu/ubtb/Bundles.scala‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ class MicroBtbEntry(implicit p: Parameters) extends MicroBtbBundle {
3636
}
3737

3838
class Slot1 extends SlotBase {
39-
// saturate counter indicating taken bias of branch in slot 1
40-
val takenCnt: SaturateCounter = new SaturateCounter(TakenCntWidth)
4139
// whether branch in slot 1 has a static target
4240
val isStaticTarget: Bool = Bool()
4341
}
@@ -49,8 +47,8 @@ class MicroBtbEntry(implicit p: Parameters) extends MicroBtbBundle {
4947
val taken: Bool = Bool()
5048
}
5149

52-
// whether the whole entry is valid
53-
val valid: Bool = Bool()
50+
// we consider an entry is valid if it has usefulCnt > 0
51+
def valid: Bool = !usefulCnt.isSaturateNegative
5452
// partial vTag = fetchBlockVAddr(TagWidth, 1)
5553
val tag: UInt = UInt(TagWidth.W)
5654
// saturate counter indicating how useful is this entry

‎src/main/scala/xiangshan/frontend/bpu/ubtb/MicroBtb.scala‎

Lines changed: 16 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,8 @@ class MicroBtb(implicit p: Parameters) extends BasePredictor with HasMicroBtbPar
6767
private val s1_hitIdx = OHToUInt(s1_hitOH)
6868
private val s1_hitEntry = entries(s1_hitIdx)
6969

70-
// we do not need to check attribute.isDirect/Indirect here, as entry.slot1.takenCnt is initialized to weak taken
71-
// and for those jumps, takenCnt will remain unchanged during training,
72-
// so e.slot1.takenCnt.isPositive is always true if e.slot1.attribute.isDirect/Indirect
73-
io.prediction.taken := s1_hit && s1_hitEntry.slot1.takenCnt.isPositive
70+
// we do always-taken prediction in ubtb
71+
io.prediction.taken := s1_hit
7472
io.prediction.cfiPosition := s1_hitEntry.slot1.position
7573
io.prediction.target := getFullTarget(s1_startVAddr, s1_hitEntry.slot1.target, s1_hitEntry.slot1.targetCarry)
7674
io.prediction.attribute := s1_hitEntry.slot1.attribute
@@ -142,12 +140,9 @@ class MicroBtb(implicit p: Parameters) extends BasePredictor with HasMicroBtbPar
142140

143141
// calculate hit flags, valid only when t0_hit
144142
private val t0_hitNotUseful = t0_hitEntry.usefulCnt.isSaturateNegative
145-
private val t0_hitPositionLow = t0_hitEntry.slot1.position > t0_position
146-
private val t0_hitPositionHigh = t0_hitEntry.slot1.position < t0_position
147143
private val t0_hitPositionSame = t0_hitEntry.slot1.position === t0_position
148144
private val t0_hitAttributeSame = t0_hitEntry.slot1.attribute === t0_attribute
149145
private val t0_hitTargetSame = t0_hitEntry.slot1.target === t0_target
150-
private val t0_hitTaken = t0_hitEntry.slot1.takenCnt.isPositive
151146

152147
/* *** train stage 1 ***
153148
* - select victim
@@ -169,24 +164,19 @@ class MicroBtb(implicit p: Parameters) extends BasePredictor with HasMicroBtbPar
169164

170165
// hit states (flags), valid only when t1_hit
171166
private val t1_hitNotUseful = RegEnable(t0_hitNotUseful, t0_valid)
172-
private val t1_hitPositionLow = RegEnable(t0_hitPositionLow, t0_valid)
173-
private val t1_hitPositionHigh = RegEnable(t0_hitPositionHigh, t0_valid)
174167
private val t1_hitPositionSame = RegEnable(t0_hitPositionSame, t0_valid)
175168
private val t1_hitAttributeSame = RegEnable(t0_hitAttributeSame, t0_valid)
176169
private val t1_hitTargetSame = RegEnable(t0_hitTargetSame, t0_valid)
177-
private val t1_hitTaken = RegEnable(t0_hitTaken, t0_valid)
178170

179171
// init a new entry
180172
private def initEntryIfNotUseful(notUseful: Bool): Unit =
181173
when(notUseful) {
182-
t1_updatedEntry.valid := true.B
183-
t1_updatedEntry.tag := t1_tag
174+
t1_updatedEntry.tag := t1_tag
184175
t1_updatedEntry.usefulCnt.resetPositive() // usefulCnt inits at strong positive, in/decrease by policy
185176
// slot1
186-
t1_updatedEntry.slot1.position := t1_position
187-
t1_updatedEntry.slot1.attribute := t1_attribute
188-
t1_updatedEntry.slot1.target := t1_target
189-
t1_updatedEntry.slot1.takenCnt.resetNeutral() // takenCnt inits at neutral (weak taken), in/decrease by policy
177+
t1_updatedEntry.slot1.position := t1_position
178+
t1_updatedEntry.slot1.attribute := t1_attribute
179+
t1_updatedEntry.slot1.target := t1_target
190180
t1_updatedEntry.slot1.isStaticTarget := true.B // inits at true, set to false when we see a different target
191181
t1_updatedEntry.slot1.targetCarry.foreach(_ := t1_targetCarry.get) // if (EnableTargetFix)
192182
// TODO: 2-taken train
@@ -198,63 +188,20 @@ class MicroBtb(implicit p: Parameters) extends BasePredictor with HasMicroBtbPar
198188
when(t1_valid) {
199189
when(!t1_hit) {
200190
// not hit
201-
// simply init a new entry
191+
// init a new entry if actually taken
202192
initEntryIfNotUseful(true.B)
203-
}.elsewhen(!t1_hitAttributeSame) {
204-
// hit, but attribute mismatch
205-
// if already not useful, init a new entry, otherwise decrease usefulCnt
193+
}.elsewhen(!t1_hitAttributeSame || !t1_hitPositionSame || !t1_hitTargetSame || !t1_actualTaken) {
194+
// hit, but attribute/position mismatch, or actually not taken
195+
// if already not useful and actually taken, init a new entry, otherwise decrease usefulCnt
206196
initEntryIfNotUseful(t1_hitNotUseful)
207-
}.elsewhen(t1_attribute.isConditional) {
208-
// attribute match, and is conditional (branch)
209-
when(
210-
// branch position match, and actual taken
211-
t1_hitPositionSame && t1_actualTaken
212-
) {
213-
// increase takenCnt
214-
t1_updatedEntry.slot1.takenCnt.value := t1_hitEntry.slot1.takenCnt.getIncrease
215-
}.elsewhen(
216-
// branch position match, and actual not taken
217-
t1_hitPositionSame && !t1_actualTaken ||
218-
// an actual taken branch is at higher address -> the predicted position is actual not taken
219-
t1_hitPositionHigh && t1_actualTaken ||
220-
// actual not taken, but predicted taken -> no matter position, the predicted position is actual not taken
221-
!t1_actualTaken && t1_hitTaken
222-
) {
223-
// decrease takenCnt
224-
t1_updatedEntry.slot1.takenCnt.value := t1_hitEntry.slot1.takenCnt.getDecrease
225-
}
226-
when(
227-
// branch position match, and both actual & predicted taken -> prediction correct, useful
228-
t1_hitPositionSame && t1_actualTaken && t1_hitTaken
229-
) {
230-
// increase usefulCnt
231-
t1_updatedEntry.usefulCnt.value := t1_hitEntry.usefulCnt.getIncrease
232-
}.elsewhen(
233-
// position mismatch -> not useful
234-
!t1_hitPositionSame ||
235-
// actual not taken -> fall through, not useful
236-
!t1_actualTaken
237-
) {
238-
// decrease usefulCnt
239-
t1_updatedEntry.usefulCnt.value := t1_hitEntry.usefulCnt.getDecrease
240-
}
241-
}.otherwise {
242-
// attribute match, and is direct / indirect jump
243-
when(!t1_hitPositionSame) {
244-
// position mismatch
245-
// if already not useful, init a new entry, otherwise decrease usefulCnt
246-
initEntryIfNotUseful(t1_hitNotUseful)
247-
}.elsewhen(t1_hitTargetSame) {
248-
// position match, and target match
249-
// increase usefulCnt
250-
t1_updatedEntry.usefulCnt.value := t1_hitEntry.usefulCnt.getIncrease
251-
}.otherwise {
252-
// position match, but target mismatch (should not happen for direct jumps unless self-modifies)
253-
// decrease usefulCnt
254-
t1_updatedEntry.usefulCnt.value := t1_hitEntry.usefulCnt.getDecrease
255-
// and, since we've seen a different target, target is not static anymore
197+
// and, if we've seen a different target, mark target as not static
198+
when(!t1_hitTargetSame) {
256199
t1_updatedEntry.slot1.isStaticTarget := false.B
257200
}
201+
}.otherwise {
202+
// everything matches, and actually taken
203+
// increase usefulCnt
204+
t1_updatedEntry.usefulCnt.value := t1_hitEntry.usefulCnt.getIncrease
258205
}
259206
}
260207

@@ -284,31 +231,4 @@ class MicroBtb(implicit p: Parameters) extends BasePredictor with HasMicroBtbPar
284231
t1_hitAttributeSame && !t1_hitPositionSame && t1_hitNotUseful
285232
)
286233
)
287-
288-
XSPerfAccumulate("mispredictAttribute", t1_valid && t1_hit && !t1_hitAttributeSame)
289-
290-
XSPerfAccumulate(
291-
"mispredictConditional",
292-
t1_valid && t1_hit && t1_hitAttributeSame && t1_attribute.isConditional && (
293-
t1_hitPositionSame && t1_actualTaken && !t1_hitTaken ||
294-
t1_hitPositionHigh && t1_actualTaken ||
295-
!t1_actualTaken && t1_hitTaken
296-
)
297-
)
298-
299-
XSPerfAccumulate(
300-
"mispredictDirect",
301-
t1_valid && t1_hit && t1_hitAttributeSame && t1_attribute.isDirect && (
302-
!t1_hitPositionSame ||
303-
!t1_hitTargetSame // should not happen unless self-modifies
304-
)
305-
)
306-
307-
XSPerfAccumulate(
308-
"mispredictIndirect",
309-
t1_valid && t1_hit && t1_hitAttributeSame && t1_attribute.isIndirect && (
310-
!t1_hitPositionSame ||
311-
!t1_hitTargetSame
312-
)
313-
)
314234
}

0 commit comments

Comments
 (0)