什么是“ rep; 没事;” 在x86汇编中意味着什么?它与“暂停”指令相同吗?


86
  • 什么rep; nop意思
  • pause指示相同吗?
  • 是否与rep nop(不含分号)相同?
  • 简单nop指令有什么区别?
  • 它在AMD和Intel处理器上的行为是否有所不同?
  • (奖金)这些说明的正式文件在哪里?

这个问题的动机

在讨论另一个问题的评论后,我意识到我不知道rep; nop;x86(或x86-64)汇编的含义。而且我在网上也找不到很好的解释。

我知道这rep是一个前缀,表示“重复下一个指令cx时间”(或者至少在旧的16位x86汇编中是这样)。根据这一维基百科汇总表,似乎rep只能与使用movsstoscmpslodsscas(但也许是对新的处理器去掉这个限制)。因此,我认为rep nop(没有分号)会重复一个nop操作cx时间。

但是,经过进一步的搜索,我变得更加困惑。似乎rep; noppause 映射到完全相同的操作码,并且pause行为与刚刚不同nop2005年的一些旧邮件说了不同的话:

  • “尽量不要消耗太多功率”
  • “仅用2字节编码就相当于'nop'。”
  • “这在英特尔上是神奇的。就像'nop,但让其他HT兄弟运行一样'”
  • “在Intel上暂停,在Athlon上快速填充”

由于这些不同的意见,我无法理解正确的含义。

它是在Linux内核(两个正在使用的i386x86_64的),这条评论在一起:/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */它也正在贝尔托斯使用,具有相同的注释。


Answers:


75

rep; nop确实与pause指令(opcode F390)相同。它可能用于尚不支持该pause指令的汇编程序。在以前的处理器上,这只是什么也没做,就像nop两个字节一样。在支持超线程的新处理器上,它用作处理器正在执行自旋循环以提高性能的提示。从英特尔的指令参考中

提高自旋等待循环的性能。当执行“旋转等待循环”时,奔腾4或Intel Xeon处理器退出循环时会遭受严重的性能损失,因为它检测到可能的内存顺序冲突。PAUSE指令向处理器提示代码序列是自旋等待循环。处理器使用此提示来避免在大多数情况下违反内存顺序,从而大大提高了处理器性能。因此,建议在所有自旋等待循环中放置一个PAUSE指令。


4
自旋等待循环一样忙等待循环?这种“改进”仅适用于超线程处理器吗?(为什么?)
DenilsonSáMaia

11
是的,旋转等待循环与繁忙等待循环相同。好处也适用于不支持超线程的CPU。可以将其视为限制管道中(不必要的)指令的数量(而不是尝试并行执行循环的多次迭代)
Brendan

1
@Brendan,谢谢!我完全不了解,直到您说了关于并行循环的事情。
法尔肯教授

11
@Brendan,哦,我明白了!这些现代处理器是超标量的,因此它们将尝试同时运行多个指令。如果这是一个忙等待循环,那么运行更多指令将不会使其更快,因为它只是在等待另一种情况。
DenilsonSáMaia的

1
@Denilson:是的,超线程友好(或者只是节省功耗而不使用HT)是一个很大的好处,但是另一个好处是可以避免在退出旋转循环时出现内存排序错误的猜测。如果没有pause,您的自旋循环实际上会比一个管道明显慢一些,以注意到另一个内核写入的内存位置的状态变化。
彼得·科德斯

14

rep nop= F3 90 =的编码pause以及在不支持的较旧CPU上的解码方式pause


lock实际上,现有的CPU会忽略不适用于指令的前缀(除外)。

该文档说,rep与不适用的指令一起使用是“保留的,可能会导致不可预期的行为”,因为将来的CPU可能会将其识别为某些新指令的一部分。 一旦他们使用建立了任何特定的新指令编码f3 xx,他们就会记录该指令如何在较旧的CPU上运行。(是的,x86操作码空间非常有限,以至于他们会做这种疯狂的事情,是的,这会使解码器变得复杂。)

在这种情况下,这意味着您可以pause在spinloops中使用而不会破坏向后compatpause英特尔的ISA ref手动输入pause保证,不知道的旧CPU会将其解码为NOP,而不会造成任何损害。在新的CPU上,您将获得省电/ HT友好的优势,并避免在旋转的内存发生更改并且退出旋转循环时避免内存排序错误


链接到x86标签Wiki信息页面上的英特尔手册和大量其他好东西

无意义rep前缀成为新CPU上的新指令的 另一种情况lzcntF3 0F BD /r。在不支持该指令(在其CPUID中缺少LZCNT功能标志)的CPU上,其解码为rep bsr,其运行方式与相同bsr。因此,在旧的CPU上,它产生32 - expected_result,并且在输入为零时未定义。

但是tzcntbsf对于非零输入也可以做同样的事情,因此tzcnt即使不能保证目标CPU将其运行为,编译器也可以使用tzcnt。AMD CPU的运行速度快tzcnt,慢bsf,而在Intel上它们都快。只要它的正确性无关紧要(您不依赖标志设置,或者在input = 0的情况下不保留目标未更改的行为),则将其解码为tzcnt支持它的CPU会很有帮助。


一种无意义的rep前缀,可能永远不会解码rep ret的情况:默认情况下,gcc在针对“通用” CPU时使用(即,不针对特定的CPU使用-march-mtune,也不针对AMD K8或K10)。可以使CPU解码rep retret,而不是,因为大多数Linux发行版的大多数二进制文件中都包含它。请参阅 `rep ret`是什么意思?


3
rep前缀也使用英特尔添加锁省略。
Paul A. Clayton

不适用于指令的前缀将被忽略。但应提到的是重复前缀(F2HF3H)保留,并可能导致不可预知的行为表11-3。前缀对SSE,SSE2和SSE3指令的影响。因此,某些指令(而不是全部指令)会忽略前缀应用程序。那么,此功能是否未记录?
圣安东尼奥

2
@ St.Antario:他们这样说是因为将来的CPU可能会将其识别为某些新指令的一部分。在所有实际的CPU上都是如此,一旦他们使用f3 xx它们建立了编码,就会记录其如何在较旧的CPU上运行。
彼得·科德斯

1
实际上,现有的CPU会忽略不适用于指令的前缀(除锁以外)。有记载的rep movbe原因#UD,所以rep并不总是被忽略。即使它不适用于REP/REPE/REPZ/REPNE/REPNZ手动输入中指定的意义上的指令。
圣安塔里奥

2
@ St.Antario:有趣!但是,一般而言,对于较旧的指令,将忽略不适用的前缀。引入新指令时,可以选择添加更严格的规则。IDK为什么他们会为此特定情况选择它。
彼得·科德斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.