在x86汇编中将寄存器设置为零的最佳方法是什么:xor,mov或?

以下所有说明都做同样的事情:设置%eax为零。哪种方式最佳(需要最少的机器周期)?

xorl %eax, %eax

mov $0, %eax

andl $0, %eax


TL; DR摘要:xor same, same是所有CPU的最佳选择。没有其他方法比它有任何优势,它至少比任何其他方法都有一些优势。它是由英特尔和AMD正式推荐的。在64位模式下,仍然使用xor r32, r32,因为写32位寄存器会将上面的32复位。 xor r64, r64是浪费一个字节,因为它需要一个REX前缀。

更糟糕的是,Silvermont只承认xor r32,r32破坏而不是64位操作数。因此,即使因为你将r8…r15归零而仍然需要REX前缀,请使用xor r10d,r10d,而不是xor r10,r10。

例子:

xor eax, eax ; RAX = 0

xor r10d, r10d ; R10 = 0

xor edx, edx ; RDX = 0

; small code-size alternative: cdq ; zero RDX if EAX is already zero

; SUB-OPTIMAL

xor rax,rax ; waste of a REX prefix, and extra slow on Silvermont

mov eax, 0 ; doesn’t touch FLAGS, but not faster and takes more bytes

归零矢量寄存器通常最好用pxor xmm, xmm。这通常是gcc所做的(甚至在使用FP指令之前)。

xorps xmm, xmm可以有意义。它比一个字节短一个字节pxor,但xorps在Intel Nehalem上需要执行端口5,同时pxor可以在任何端口(0/1/5)上运行。(Nehalem在整数和FP之间的2c旁路延迟延迟通常是不相关的,因为无序执行通常可以在新的依赖链的开始处隐藏它)。

在SnB系列微体系结构中,xor-zeroing的味道都不需要执行端口。在AMD和预Nehalem的P6 / 2英特尔,xorps和pxor被处理的相同方式(如向量整数指令)。

使用AVX版本的128b向量指令也会将reg的上半部分vpxor xmm, xmm, xmm归零,因此对于归零YMM(AVX1 / AVX2)或ZMM(AVX512)或任何将来的向量扩展是一个很好的选择。 vpxor ymm, ymm, ymm但是,不需要任何额外的字节来编码,并且运行相同。AVX512 ZMM归零将需要额外的字节(对于EVEX前缀),因此应首选XMM或YMM归零。

有些CPU认为sub same,same是类似的归零xor,但所有识别任何归零习惯用语的CPU都能识别xor。只需使用xor,您就不必担心哪个CPU识别哪个归零成语。

xor(作为公认的归零成语,不像mov reg, 0)有一些明显的和一些微妙的优点(摘要列表,然后我将扩展那些):

代码大小比mov reg,0。(所有CPU)

避免对以后的代码进行部分寄存器处罚。(英特尔P6系列和SnB系列)。

不使用执行单元,节省电力并释放执行资源。(英特尔SnB系列)

较小的uop(没有立即数据)在uop缓存行中留出空间,以便在需要时附近的指令借用。(英特尔SnB系列)。

不会使用物理寄存器文件中的条目。(英特尔SnB系列(和P4)至少可能是AMD,因为他们使用类似的PRF设计而不是像ROB P6系列微架构那样在ROB中保持寄存器状态。)

较小的机器代码大小(2个字节而不是5个)始终是一个优势:更高的代码密度导致更少的指令缓存未命中,更好的指令获取和潜在的解码带宽。

在Intel SnB系列微体系结构上不使用 xor 执行单元的好处很小,但节省了功耗。它更可能与SnB或IvB有关,它只有3个ALU执行端口。Haswell以及后来有4个执行端口可以处理整数ALU指令,包括mov r32, imm32,所以通过调度程序完美决策(实际上不会发生),HSW仍然可以维持每个时钟4个uop,即使它们都需要执行端口。

有关更多详细信息,请参阅我关于归零寄存器的另一个问题的答案。

Bruce Dawson的博客帖子 Michael Petch链接(在对问题的评论中)指出xor在注册重命名阶段处理而不需要执行单元(在未融合域中为零uops),但错过了它仍然是一个uop的事实在融合域中。现代英特尔CPU可以每个时钟发出和退出4个融合域uop。这就是每时钟限制4个零的来源。寄存器重命名硬件的复杂性增加只是将设计宽度限制为4的原因之一。(Bruce撰写了一些非常优秀的博客文章,比如关于FP数学和x87 / SSE /舍入问题的系列文章,我这样做了极力推荐)。

在AMD Bulldozer系列CPU上,mov immediate运行在相同的EX0 / EX1整数执行端口上xor。mov reg,reg也可以在AGU0 / 1上运行,但这仅用于寄存器复制,而不是用于设置。所以,据我所知,在AMD公司唯一的优势xor过分mov的是较短的编码。它也可能节省物理寄存器资源,但我还没有看到任何测试。

公认的归零成语避免了对Intel CPU的部分寄存器处罚,后者将部分寄存器与完整寄存器(P6和SnB系列)分开重命名。

xor将标记寄存器为具有上部归零,所以xor eax, eax/ inc al/ inc eax避免了通常的局部寄存器惩罚该IVB预CPU具有。即使没有xor,当AH修改高8位()然后读取整个寄存器时,IvB只需要合并uop ,而Haswell甚至会删除它。

来自Agner Fog的微型指南,第98页(Pentium M部分,后面的部分包括SnB参考):

处理器将自身的XOR识别为将其设置为零。寄存器中的特殊标记会记住寄存器的高位为零,因此EAX = AL。即使在循环中也会记住此标记:

; Example    7.9. Partial register problem avoided in loopxor    eax, eaxmov    ecx, 100

LL:

mov    al, [esi]mov    [edi], eax    ; No extra uopinc    esiadd    edi, 4dec    ecxjnz    LL

(来自第82页):只要您没有得到中断,错误预测或其他序列化事件,处理器就会记住EAX的高24位为零。

该引导件的pg82还证实,mov reg, 0被未识别为归零成语,至少在早期的设计P6像PIII或PM。如果他们花费晶体管在后来的CPU上检测它,我会感到非常惊讶。

xor设置标志,这意味着在测试条件时必须小心。由于setcc遗憾的是只能使用8位目的地,因此您通常需要注意避免部分注册处罚。

如果x86-64将一个被移除的操作码(如AAM)重新用于16/32/64位setcc r/m,并且在r / m字段的源寄存器3位字段中编码谓词,那就太好了一些其他单操作数指令将它们用作操作码位)。但他们没有这样做,无论如何这对x86-32没有帮助。

理想情况下,您应该使用xor/ set flags setcc//读取完整寄存器:

call some_func

xor ecx,ecx ; zero before the test

test eax,eax

setnz cl ; cl = (some_func() != 0)

add ebx, ecx ; no partial-register penalty here

这在所有CPU上都具有最佳性能(无停顿,合并uop或错误依赖)。

当你不想在标志设置指令之前进行xor时,事情会变得更复杂。例如,你想在一个条件上分支,然后在同一个标志的另一个条件下setcc。例如cmp/jle,sete您要么没有备用寄存器,要么完全不使用xor未采用的代码路径。

没有公认的归零成语不会影响标志,因此最佳选择取决于目标微体系结构。在Core2上,插入合并uop可能会导致2或3个周期停顿。它似乎在SnB上更便宜,但我并没有花太多时间来测量。使用mov reg, 0/ setcc会对较旧的英特尔CPU造成重大损失,并且在较新的英特尔上仍然会有所改善。

如果你不能在标志设置指令之前进行xor-zero,那么使用setcc/ movzx r32, r8可能是Intel P6和SnB系列的最佳选择。这应该比在xor-zeroing之后重复测试更好。(甚至不考虑sahf/ lahf或pushf/ popf)。IvB可以消除movzx r32, r8(即使用寄存器重命名处理它,没有执行单元或延迟,如xor-zeroing)。Haswell后来只消除了常规mov指令,所以movzx需要一个执行单元并且具有非零延迟,使得test / setcc/ movzx比xor/ test / 差setcc,但仍然至少和test / mov r,0/ 一样好setcc(并且在旧CPU上要好得多)。

在AMD / P4 / Silvermont上使用setcc/ movzx没有归零是不好的,因为它们不会分别跟踪子寄存器的deps。寄存器的旧值会有一个错误的缺陷。当/ test / 不是一个选项时,使用mov reg, 0/ setcc进行归零/依赖性破坏可能是最好的选择。xorsetcc

当然,如果您不需要setcc输出宽于8位,则不需要将任何内容归零。但是,如果选择最近属于长依赖关系链的寄存器,请注意除P6 / SnB之外的CPU的错误依赖性。(如果你调用一个可以保存/恢复你正在使用的寄存器的函数,请注意引起部分注册失效或额外的uop。)

and具有立即零并不是特殊的,与我所知的任何CPU上的旧值无关,因此它不会破坏依赖链。它没有优点xor,也有许多缺点。

请参阅http://agner.org/optimize/获取microarch文档,包括哪些归零成语被识别为依赖性破坏(例如sub same,same,在某些但不是所有CPU上,而在所有CPU xor same,same上都被识别。) mov确实打破了旧值的依赖关系链寄存器(无论源值如何,零或不,因为这是mov有效的)。 xor只有在src和dest是同一个寄存器的特殊情况下才会断开依赖链,这就是为什么它被mov排除在特别识别的依赖断层列表之外。(另外,因为它不被认为是归零成语,具有其他好处。)

有趣的是,最古老的P6设计(PPro到Pentium III)并没有认识到xor- 为了避免部分寄存器停顿而仅仅作为归零用语,因此在某些情况下值得使用两者。(参见Agner Fog的例子6.17。在他的microarch pdf中。他说这也适用于P2,P3,甚至(早期?)PM。 对链接博客文章的评论说只有PPro有这种疏忽,但我’我们在Katmai PIII上进行了测试,并且@Fanael在Pentium M上进行了测试,我们都发现它没有打破延迟限制imul链的依赖性。)

如果它确实使您的代码更好或保存指令,那么确保零,mov以避免触摸标志,只要您不引入除代码大小之外的性能问题。但是,避免使用破坏标志是不使用的唯一合理理由xor。

在x86汇编中将寄存器设置为零的最佳方法是什么:xor,mov或?相关推荐

  1. X86汇编——标志寄存器

    FLAGS标志寄存器由一组状态标志.一个控制标志以.一组系统标志以及一部分保留未使用的位所组成.其状态标志用于表示逻辑或算术运算的结果,系统标志提供给操作系统使用. 在16位汇编中,我们可以使用16位 ...

  2. linux汇编push,在x86汇编中寄存器上使用的push / pop指令的功能是什么?

    在阅读有关汇编程序的文章时,我经常遇到人们在写文件时他们推送处理器的某个寄存器并稍后再次弹出它以恢复它之前的状态. 怎么能推一个寄存器? 它在哪里推? 为什么需要这个? 这可归结为单处理器指令还是更复 ...

  3. python3设置编码背景颜色_在pythongtk3中设置条目背景颜色并设置回defau的最佳方法...

    我将首先解决您提到的问题,因为这些问题可以深入了解GTK和OP的代码.主要问题的答案(以及执行此操作的适当代码)位于答案的底部.If I insert a text, not containing s ...

  4. X86_64 GNU汇编、寄存器、内嵌汇编

    文章目录 一.汇编语言 二.指令 数据传输指令 栈操作指令 push pop 运算指令 位操作 比较操作指令 标志寄存器 流控制指令 三.伪指令 .equ .rept .endr .lcomm .gl ...

  5. 汇编中各寄存器的作用(16位CPU14个,32位CPU16个)和 x86汇编指令集大全(带注释)

    From:https://www.cnblogs.com/zimmerk/articles/2520011.html From:https://blog.csdn.net/bjbz_cxy/artic ...

  6. X86汇编常见的寄存器

    X86汇编常见的寄存器 4个数据寄存器(EAX.EBX.ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP) 6个段寄存器(ES.CS.SS.DS.FS和GS) ...

  7. 汇编中各寄存器的作用(16位CPU14个,32位CPU16个)和 x86汇编指令集大全(带注释)...

    From:https://www.cnblogs.com/zimmerk/articles/2520011.html From:https://blog.csdn.net/bjbz_cxy/artic ...

  8. X86汇编---寄存器+指令

    文章目录 X86汇编常见的寄存器 x86汇编指令集大全 X86汇编常见的寄存器 4个数据寄存器(EAX.EBX.ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP ...

  9. 寄存器理解 及 X86汇编入门

    本文整理自多材料源,感谢原址分享,请查看末尾Url I, 汇编语言分类: 汇编语言和CPU息息相关,但是不能把汇编语言完全等同于CPU的机器指令.不同架构的CPU指令并不相同,如x86,powerpc ...

最新文章

  1. 如何画正太分布曲线_图解统计学 01 | 神奇的正态分布
  2. SQL Server 跨库同步数据
  3. 使用httpclient4.3.2来实现微信临时素材的上传
  4. Linux kernel进行编译时提示No rule to make target `menconfig'
  5. P1494 [国家集训队]小Z的袜子/莫队学习笔记(误
  6. Python数据处理Tips使用OpenCV预处理图像数据的10种操作
  7. C/C++的刷题练习之牛客网,一个友好的网站
  8. 老树开新花,慧聪尚能饭否?
  9. outlook中网址连接打不开解决办法
  10. 【转】我从罗振宇、脱不花得到的10点
  11. UE的Blend Profile
  12. antd表单设置默认值
  13. 网站api自己怎么写_网站seo优化中文章标题怎么写?
  14. GAN论文详细解读+思想
  15. 马来西亚:央行与证监会联合实施数字货币与ICO监管
  16. IOS 定位城市和切换城市
  17. 【模拟IC】二级运放2:单位增益负反馈
  18. 985研究生入职电网6个月,晒出收入,还以为看错了,kafka实战pdf
  19. 乐高 计算机泡泡龙教案,小班科学教案:泡泡龙的秘密.doc
  20. 2022-4-11 Leetcode 435.无重叠区间 —— 【贪心算法】

热门文章

  1. 获取当前时间一年后的日期
  2. Spark生态系统和运行架构
  3. 【大数据】快速了解大数据计算服务
  4. 软件项目中的质量管理
  5. Multisim高频电子线路2.7章LC谐振电路的仿真
  6. Vue 和 React 的区别
  7. Citrix 服务器虚拟化之十四 介绍桌面虚拟化之XenDesktop 7.0
  8. 电脑c盘变红满了的清理方法
  9. 百度SEO HTML5蓝色个人主页博客整站模板
  10. 装载M1芯片的Mac安装“AE”时,出现错误代码“501”怎么办?