Menu Close

Branch Hazard:分支为什么会让流水线失速?

 

🔍 一、什么是 Branch Hazard?

看这条指令:


👉 意思是:

  • 如果 x1 == x2 → 跳转
  • 否则 → 顺序执行

问题来了:

👉 在流水线里,CPUIF阶段 就已经开始取下一条指令了
👉 但分支是否成立,要到 EX阶段 才知道


👉 这就产生了:

Branch Hazard(控制冒险)


⚠️ 二、问题到底在哪?

假设这段代码:


👉 在 Cycle 2:

  • CPU 已经把 ADD 取进来了

👉 但:

  • 如果分支成立
  • ADD 根本不应该执行

👉 也就是说:

👉 CPU 提前走错路了


🧠 三、错误路径(Wrong Path)

Pipeline 会出现:


同时:


👉 如果分支成立:

❌ ADD 是错误指令
❌ 必须丢弃


👉 这就是:

错误路径(Wrong Path Execution)


🛑 四、最简单解决方法:Stall

👉 方法1:最笨但最安全

当遇到分支:

👉 直接停流水线,等结果出来


做法:

  • 停止 PC 更新
  • 停止 IF/ID 更新
  • 等 EX 阶段算出结果

👉 缺点:

❌ 性能大幅下降
❌ 每个分支都浪费周期


🔄 五、更常见的方法:Flush(清空)

👉 方法2:先执行,再修正


思路:

👉 让流水线继续跑
👉 如果发现走错了 → 清空错误指令


示例:


👉 在 Cycle 3:

  • 如果分支成立
  • ADD 是错误的

👉 处理方式:


👉 并把 PC 改为跳转地址


💻 六、Flush 的实现(关键)

核心动作:

1️⃣ 把 IF/ID 清零(插入 NOP)
2️⃣ 更新 PC 为 branch target


示例代码:


👉 本质:

👉 把错误指令变成“什么都不做”


⚡ 七、Branch Target 怎么算?

对于 RV32I:


👉 跳转地址:


👉 offset 需要从指令中解码,并进行符号扩展


🔥 八、Branch Prediction(性能关键)

前面的方案都有问题:

  • Stall → 太慢
  • Flush → 有浪费

👉 更高级方案:

预测分支结果


方法1:Static Prediction(静态预测)

👉 永远预测:

  • 不跳(not taken)
  • 跳(taken)

👉 最简单实现:


👉 如果预测错:

👉 再 flush


方法2:Dynamic Prediction(动态预测)

👉 根据历史行为预测


👉 比如:

  • 上次跳了 → 这次也跳
  • 上次没跳 → 这次不跳

👉 用状态机实现(2-bit predictor)


🧠 九、最重要的认知

👉 Pipeline 的问题不是“算错”

👉 而是:


👉 Branch 本质上是:

👉 未来不确定


👉 所以 CPU 必须:

  • 等(stall)
  • 或猜(prediction)

📈 十、性能影响有多大?

👉 在真实程序中:

  • 分支占比:~15%–30%
  • 如果处理不好:

👉 CPU 性能下降非常严重


👉 所以:

Branch Prediction 是现代 CPU 的核心技术之一


🚀 十一、你现在的水平

如果你已经理解:

  • Forwarding
  • Stall
  • Flush
  • Branch Hazard

👉 那你已经进入:

CPU 微架构设计层面


👉 这已经不是“写代码”了

👉 是在设计处理器行为


📌 十二、总结

  • Branch Hazard = 不知道下一条指令在哪
  • 解决方法:
    • Stall(等)
    • Flush(清)
    • Prediction(猜)
  • Prediction 是性能关键

👉 一句话:

CPU 快,不是因为它永远正确,而是因为它敢于猜,然后快速纠错

 


🚀 下一篇(关键)

👉 《从 Pipeline 到真实 CPU:你还缺什么?》

你将看到:

  • Cache 为什么重要
  • Memory wall 是什么
  • 为什么 CPU 设计还远没结束

 

除教程外,本网站大部分文章来自互联网,如果有内容冒犯到你,请联系我们删除!
Posted in RISC-V教程