我正在努力理解数据依赖和控制依赖之间的区别。
所以我看到的一个例子是:
数据依赖,例如,指令使用由另一条指令创建的数据
控制相关性,例如,指令等待更新的 reg 进行比较
我很难理解的是,例如在 beq 我等待寄存器更新但我也依赖他的数据。
所以我不知道如何知道它们之间的区别。
我正在努力理解数据依赖和控制依赖之间的区别。
所以我看到的一个例子是:
数据依赖,例如,指令使用由另一条指令创建的数据
控制相关性,例如,指令等待更新的 reg 进行比较
我很难理解的是,例如在 beq 我等待寄存器更新但我也依赖他的数据。
所以我不知道如何知道它们之间的区别。
指令等待更新 reg 进行比较是对控制依赖的错误描述,难怪
在可以检查分支条件之前,条件分支指令本身对其输入寄存器具有数据依赖性。
分支之后的指令对分支具有控制依赖性。 前端需要根据是否采用分支来了解要获取/解码哪些指令。(或者对于间接分支,目标地址是什么)。
分支预测做出的猜测可能后来被发现是错误的。(当分支指令实际执行并检查预测时)。
在简单(标量)有序流水线中,相关指令无法在分支指令之前到达 exec 阶段。从分支错误预测中发现和恢复只是意味着重新引导前端从正确的地址获取,丢弃来自错误路径的已获取(和解码)的指令。
但是在可能发生的乱序执行 CPU 中。特别是如果分支的输入是长依赖链的一部分,但具有控制依赖关系的指令没有数据依赖关系。(即它们是独立的工作,乱序的后端可以推测性地开始。)
当预测正确时,分支预测 + 推测执行有效地隐藏了控制依赖关系。这就是为什么编译器经常会转换if (a==0) return a;
成if (a==0) return 0;
类似的;如果他们无论如何都要分支(控制依赖),请使用返回值打破/避免代码的数据依赖。
有关的:
当 Skylake CPU 错误预测分支时,究竟会发生什么?- 一个现代的 OoO exec CPU。
通过提前计算条件来避免停止流水线- 最小化分支本身的数据依赖链的长度,以便它可以及早执行并验证分支预测。
依赖链分析提到了循环分支的控制依赖。
CPU 预测和内存屏障——经过分支的推测性执行可能会引入内存重新排序。
为什么条件移动不易受到分支预测失败的影响?- CMOV 纯粹是 ALU 选择操作,只是数据依赖,不是控制依赖。