我试图找出 x86 处理器在遇到存储条件指令时会做什么。例如,它是否会停止管道的前端并等待 ROB 缓冲区变空,然后再停止停止前端并执行 SC?基本上它会迫使处理器变得非投机性......
我猜您指的是
CMOVcc
说明。
我不了解较旧的 x86 处理器,但现代处理器(自从它们变得投机且无序)将条件存储实现为:
old value = mem[dest address]
if (condition)
mem[dest address] = new value
else
mem[dest address] = old value
条件部分可以像这样在硬件中实现:
cond
|\ |
----| \|
new | \
| | dest
| |---------
| | |
__| / |
| | / |
| |/ |
|____________|
所以没有必要打破猜测。事实上,商店将会出现。该条件决定要写入的数据是旧值还是新值。
与 ARM 和许多其他 RISC 不同,x86 没有 加载链接/存储条件;从架构上来说,它有类似
lock add byte [rdi], 1
或 lock cmpxchg [rdi], ecx
的原子 RMW 之类的东西。有关语义和 CPU 架构的一些详细信息,请参阅 num++ 对于“int num”可以是原子的吗?。
另请参阅 x86 等效的 LWARX 和 STWCX - 任意原子 RMW 操作可以通过 与 CAS (lock cmpxchg
) 重试循环合成。与 LL/SC 不同,它容易受到 ABA 问题的影响,但 CAS 是为原子内容提供构建块的另一种主要方法。
在 MESI 修改状态下对该行进行缓存锁定(而不是传统的总线锁定)取决于它是可缓存内存,并且对齐或至少不跨越缓存行边界进行分割。
cmov
指令只有一种形式,带有寄存器目标,而不是内存。
cmovcc reg, reg/mem
。即使有内存源,它也是无条件加载来提供 ALU 选择操作,因此即使条件为假,也会在错误地址上出现段错误。 (与 ARM 谓词指令不同,ARM 谓词指令在错误条件下会被 NOP 出。)我猜你可能会说
lock cmpxchg [mem], reg
是一个条件存储,但唯一可能的条件是内存的旧内容是否与 AL/AX/EAX/RAX 匹配。https://www.felixcloutier.com/x86/cmpxchg
rep stosb/w/d/q
也是一个条件存储,如果你安排RCX为0或1(例如xor ecx,ecx
/ set FLAGS /
setcc cl`);微代码分支不是分支预测的,因此它与正常分支有点不同。AVX
vmaskmovps
或 AVX-512 屏蔽存储是真正的条件存储,基于屏蔽条件。我在
cmov
的另一个问答中的回答讨论了这些的条件负载等价物,以及
cmov
不是条件负载,它是需要所有 3 个输入(标志和 2 个整数)的 ALU 选择。 除了 LL/SC 对的 SC 部分之外,条件存储在大多数 ISA 中很少见。 32 位 ARM 是一个例外。请参阅 为什么后来的 ARM 指令集中不存在条件执行指令? 了解为什么 AArch64 放弃了它。
不会导致管道停顿。请参阅 https://agner.org/optimize/ 和 https://uops.info/ 了解一些性能数据以及英特尔的优化手动的。它们抑制屏蔽元素上的错误。如果您在提交到 L1d 之前重新加载,则来自它们的存储转发可能会阻止该加载,但不会阻止整个管道。
(高级性能扩展)为传统整数指令(如 sub
)添加了 REX2 和 EVEX 前缀,以及
cmov
的一些新编码,这些编码实际上确实抑制了错误条件下的负载故障,以及条件存储版本。他们使用助记符 CFCMOVcc
,即有条件故障 CMOV。英特尔最终决定进行需要 64 位模式的扩展,使用通过删除 BCD 和其他操作码释放的一些编码空间。大概硬件处理类似于 AVX-512 屏蔽的条件加载/存储。