xs-gem5 间接分支目标预测架构 (BTB-ITTAGE)

当前 xs-gem5 的 Kunminghu v3 默认前端(DecoupledBPUWithBTB)预测普通间接控制流的目标

  • BTB 给出控制流候选和基础目标
  • BTB-ITTAGE 用路径历史选择/覆盖普通间接分支目标
  • RAS 覆盖 return

这里的“普通”指 isIndirect && !isReturn,涵盖间接 call 和非 return 的间接 jump;return 的目标由 RAS 处理,不是 ITTAGE 的职责

默认配置

configs/example/kmhv3.pybp_type == DecoupledBPUWithBTB 时启用 mbtbittageras 等组件,并将 cpu.branchPred.ittage.resolvedUpdate = True, 并会使用 BTBITTAGE

BTBITTAGE 的默认参数定义在 src/cpu/pred/BranchPredictor.py

项目 默认值 含义
表数 5 5 个 tagged 表
表项数 [256, 256, 512, 512, 512] 每张表直接索引的容量
tag 每表 9 bit 与完整 entry.pc 二次核对共同防 alias
历史长度 [4, 8, 13, 16, 32] 从短到长的路径相关性
索引块大小 32 B index/tag 以 stream 的 32B 对齐块地址为 PC 成分
延迟 2 stagePreds[2] 起写入候选目标
每次分配 1 表项 一次失误至多分配一个更长历史表项
  • 顶层 predictWidth 是 64B,而 ITTAGE 的索引块是 32B;它使用预测 stream 的 startPC(经 >> 5)索引,而不是每一条间接分支的 PC
  • entry 同时保存完整的 pc,查找时要求 tagpc 都一致

预测 Path

FullBTBPrediction::getEntryTarget() 是最终目标选择的唯一汇合点:

  1. 直接分支使用 BTBEntry::target
  2. 普通间接分支先取 BTBEntry::target 作为基础目标;如果 indirectTargets 中存在同一 branch PC 的条目,则使用 ITTAGE 给出的目标覆盖它
  3. return 无条件使用 returnTarget,即 RAS 结果;ITTAGE 从不查询、更新或统计 return。

因此,BTB target 既是 ITTAGE miss 的功能性回退,也是 ITTAGE 的 alternate/base 候选

createFetchTargetEntry() 会把已选择的最终 target 写进 predBranchInfo.target,随后前端据 finalPred.getTarget() 推进下一个 s0PC

顶层还记录 S3 归因:

  • 当预测的 taken entry 是普通间接分支且 ittage->tageHit() 为真时,finalPred.s3Source 标为 ITTAGE
  • return 标为 RAS

BTB-ITTAGE lookup

BTBITTAGE::putPCHistory() 对当前 stream 仅为每张表读取一个 (index, tag, entry)

1
2
3
index = ((startPC >> log2(32)) XOR folded_path_history) XOR ASID hash
tag = (startPC >> log2(32)) XOR folded_path_history
XOR (alternate_folded_history << 1) 注入 ASID hash 后截断

随后 lookupHelper() 遍历当前 stage 的 BTB entry,仅接受 valid && isIndirect && !isReturn 的 entry,并从最长表向最短表找两个命中:

  • 命中条件:表项 valid、预测 tag 相等,且表项保存的完整 pc == btb_entry.pc
  • 第一个命中是 main provider,第二个是 alternate provider;两者都没有时使用 BTB 基础 target
  • main provider 的 2-bit counter 不为 0 时,使用 main 的 target:
    • counter >= 2 才会把该目标写入 indirectTargets
    • counter == 1 的 main 命中会提供目标但不产生覆盖条目,最终仍落回 BTB target
  • main counter == 0 时,若存在 alternate 则由 alternate 决定;否则使用基础 BTB target。(这一类选择记为 useAlt,其中也包括“不命中而用 BTB”)

当前实现将每表存储抽象为单个 TageEntry(不是 BTBTAGE 的多 way 结构):{valid, tag, target, 2-bit counter, useful, pc}
虽然 ITTAGE 根据“最长优先”寻找多个命中,但每张表对一个 stream 只有一次读取,所以同一 stream 中不同间接 PC 会竞争同一索引位置;完整 PC 比较防止错误命中,但不能避免容量/冲突导致的 miss

BTB-ITTAGE Path History Register (PHR)

ITTAGE 使用 PHR,不用 GHR

  • 每个硬件线程维护三组、每表一份的 PathFoldedHist:index folded history、tag folded history 与 alternate-tag folded history
  • PHR 只在预测到 taken 控制流时更新
  • 顶层 getPHistUpdate() 取最终 selected entry 的 (pc, target)
  • pHistShiftIn()pathHash(pc, target)(branch PC 的 9 bit 与 target 的 15 bit 组合)混入 970-bit PHR
  • ITTAGE 同时用更新前的 PHR 调 PathFoldedHist::update(),确保下一次查表使用与顶层投机 PHR 一致的折叠值

每个 FTQ FetchTarget 保存预测时的 PHR 与各组件的 prediction meta;
ITTAGE meta 中还保存三组 folded history 和按 branch PC 保存的 provider/alternate 信息

squash recovery

控制流 squash 时:

  1. 顶层恢复 FTQ entry 保存的 PHR
  2. BTBITTAGE::recoverPHist() 从该 entry 的 meta 恢复 folded history
  3. 用真实的 (squash PC, redirect target) 重新注入正确的 taken path
  4. 顶层也将相同真实路径写回 PHR

这避免错误间接 target 污染后续 ITTAGE 的 index/tag 路径上下文

训练 Path

默认 v3 的 ITTAGE 是 resolve-time training

fetch.cc 将 IEW 送来的 resolved CFI 聚合到 resolve queue;
DecoupledBPUWithBTB::resolveUpdate()resolvedUpdate 组件调用 doResolveUpdate(),其默认实现就是 update()
(配置中 ITTAGE 的 resolvedUpdate=True,所以它不会在随后 commit 的 updatePredictorComponents() 再训练一次)

BTBITTAGE::update() 的训练集合为当前 FTQ stream 中的普通间接 branch;
在 resolved-update 模式下还要求 entry 已被 markCFIResolved() 标记

对每个 entry:

  1. 从 FTQ 保存的 meta 取 prediction 时的 main/alternate provider 和折叠历史,真实 target 为 stream.exeBranchInfo.target
  2. 若 main 命中,以“main target 是否等于真实 target”更新 2-bit counter;
    • counter 降到 0 时用真实 target 覆盖该表项 target
    • main 与 alternate 的 taken 判断不同时,main entry 的 useful 设为 main target 是否正确
  3. 若此次是该 branch 的 control squash,且不是“选择 alternate 但 main 恰好正确”,则尝试在 main provider 之后的更长历史表分配
    • 只选 useful == 0 的候选槽
    • LFSR 随机选择后最多分配一个,初值为 {target=真实 target, counter=2, useful=false, pc=branch PC}
  4. 若可分配槽长期耗尽,usefulResetCnt 累积到 256 后清零所有表项的 useful 位

相关代码

  1. 默认配置: configs/example/kmhv3.py
  2. 参数、时延与顶层配置: src/cpu/pred/BranchPredictor.py
  3. 最终间接/return target 覆盖规则: src/cpu/pred/btb/common.hhFullBTBPrediction::getEntryTarget()
  4. 预测、S3 source、FTQ/meta 保存: src/cpu/pred/btb/decoupled_bpred.ccrequestNewPrediction()generateFinalPredAndCreateBubbles()createFetchTargetEntry()
  5. PHR 投机更新与 squash 恢复: src/cpu/pred/btb/decoupled_bpred.ccupdateHistoryForPrediction()recoverHistoryForSquash()
  6. ITTAGE 查表、训练、恢复和提交统计: src/cpu/pred/btb/btb_ittage.cc
  7. resolve queue 到预测器训练的接口: src/cpu/o3/fetch.ccsrc/cpu/pred/btb/decoupled_bpred.ccresolveUpdate()