assembly 计数为零的x86 rep前缀:发生了什么

olmpazwi  于 2023-06-06  发布在  其他
关注(0)|答案(1)|浏览(154)

如果x86 rep前缀的初始计数为零,会发生什么情况?
Intel's manual明确表示这是一个while count != 0循环,测试位于顶部,这是正常的预期行为。
但是我在其他地方看到的许多模糊的报告中,大多数都表明没有对零进行初始测试,所以它就像是一个倒计时,在最后进行测试,所以如果它是repeat{… count —=1; }until count == 0;,或者谁知道呢,那就是灾难。

wwwo4jvm

wwwo4jvm1#

当RCX=0时,什么也不会发生; rep前缀 do 首先检查零,就像伪代码所说的那样。(与loop指令不同,它完全类似于do{}while(--ecx)dec rcx/jnz的底部,但不影响FLAGS。
我想我很少听说过这被用作条件加载or storerep lodswrep stosw的习惯用法,计数为0或1,特别是在cmov之前的糟糕日子里。(cmov是一个无条件的加载,它提供ALU选择操作,所以它需要一个有效的地址,不像rep lods的计数为零。)这是没有效率的,特别是对于现代x86上的rep stos,使用快速字符串微代码(P6和更高版本),特别是没有像快速短重复移动(Ice Lake IIRC)这样的东西。
这同样适用于将前缀视为repz/repnz(cmps/scas)而不是无条件rep(lods/stos/movs)的指令。进行零次迭代意味着它们不修改FLAGS。
如果你想在repe/ne cmps/scas之后检查FLAGS,你需要确保计数值不为零,或者FLAGS已经被设置,这样你就可以以一种有用的方式分支零长度的缓冲区。(也许是通过对稍后需要的寄存器进行异或置零。)
rep movsrep stos从P6开始就在CPU上有快速字符串微码,但启动开销使它们不值得,特别是当大小可能很短和/或数据可能不对齐时。它们在不能自由使用XMM寄存器的内核代码中更有用。最近的一些CPU,如Ice Lake,具有快速短重复的微码,我认为这应该减少小计数的启动开销。
repe/ne scas/cmps在大多数CPU上 * 没有 * 快速字符串微代码,只有在最近的CPU上,如Sapphire急流和桤木Lake P-cores。所以它们非常慢,根据https://agner.org/optimize/https://uops.info/的测试,每个时钟周期加载一次(因此cmpsb/w/d/q每个计数2个周期)。

相关问题