Pet*_*des 17
对于大多数具有固定宽度指令的体系结构,答案可能是mov符号扩展或反转立即或mov /高对的无聊指令.例如在ARM上,mvn r0, #0(move-not).请参阅Godbolt编译器资源管理器中的 x86,ARM,ARM64和MIPS的gcc asm输出.IDK关于zseries asm或机器代码的任何信息.
在ARM中,eor r0,r0,r0明显比mov-immediate差.它取决于旧值,没有特殊情况处理.内存依赖性排序规则防止ARM uarch特殊包装,即使他们想要. 对于大多数其他具有弱有序内存但不需要障碍的RISC ISA也是如此memory_order_consume(在C++ 11术语中).
x86 xor-zeroing因其可变长度指令集而特殊.从历史上看,8086 xor ax,ax直接快速,因为它很小.由于这个成语被广泛使用(并且归零比全部更常见),CPU设计者给予了特殊支持,现在xor eax,eax比mov eax,0Intel Sandybridge系列和其他一些CPU 更快,即使不考虑直接和间接代码大小效果.请参阅在x86汇编中将寄存器设置为零的最佳方法是什么:xor,mov或?因为我已经能够挖掘出许多微观建筑的好处.
如果x86有一个固定宽度的指令集,我想知道是否mov reg, 0会得到与xor-zeroing一样多的特殊处理?也许,因为写入low8或low16之前的依赖性破坏很重要.
最佳性能的标准选项:
mov eax, -1:5个字节,使用mov r32, imm32编码.(mov r32, imm8不幸的是,没有任何符号扩展).所有CPU都具有出色的性能.6个字节用于r8-r15(REX前缀).mov rax, -1:7个字节,使用mov r/m64, sign-extended-imm32编码.(不是版本的REX.W = 1版本eax.那将是10字节mov r64, imm64).所有CPU都具有出色的性能.通常以牺牲性能为代价来节省一些代码大小的奇怪选项:
xor eax,eax/dec rax(或not rax):5个字节(32位为4个字节eax).缺点:前端有两个uops.在最近的英特尔上,调度程序/执行单元仍然只有一个未融合域uop,其中xor-zeroing在前端处理. mov-immediate总是需要一个执行单元.(但整数ALU吞吐量很少是可以使用任何端口的指令的瓶颈;额外的前端压力是问题)xor ecx,ecx/lea eax, [rcx-1] 5个字节总共2个常量(6个字节rax):留下一个单独的归零寄存器.如果您已经想要一个归零寄存器,那么这几乎没有任何缺点. lea可以在比mov r,i大多数CPU 上更少的端口上运行,但由于这是新依赖关系链的开始,因此CPU可以在发出后的任何备用执行端口循环中运行它.
相同的技巧适用于任何两个附近的常量,如果你做的第一个mov reg, imm32和第二个lea r32, [base + disp8].disp8的范围是-128到+127,否则你需要一个disp32.
or eax, -1:3个字节(4个用于rax),使用or r/m32, sign-extended-imm8编码.缺点:对寄存器旧值的错误依赖.
push -1/pop rax:3个字节.慢但很小.建议仅用于漏洞/代码高尔夫. 适用于任何sign-extended-imm8,与大多数其他版本不同.
缺点:
rax例如,在Skylake上执行后,存储/重载延迟意味着将不会准备好约5个周期.rsp直接读取它将需要堆栈同步uop.(例如,for add rsp, 28或for mov eax, [rsp+8]).将向量寄存器设置为all-1 pcmpeqd xmm0,xmm0是特殊的,在大多数CPU上作为依赖性破坏(不是Silvermont/KNL),但仍然需要一个执行单元来实际写入那些. pcmpeqb/w/d/q所有的工作,但q在某些CPU上速度较慢.
AVX/AVX2版本也是最佳选择. 将__m256值设置为所有ONE位的最快方法
AVX512比较仅适用于屏蔽寄存器(如ymm)作为目标,因此编译器目前正在使用vpcmpeqd ymm0, ymm0, ymm0512b all-one成语.(0xff使3输入真值表的每个元素成为a vmovdqa).这不是特殊的,因为KNL或SKL上的依赖性破坏,但它在Skylake-AVX512上具有每时钟2个吞吐量.这比使用更窄的依赖性破坏AVX全能并广播或改组它更好.
如果需要在循环内重新生成all-one,显然最有效的方法是使用a vpcmpeqd来复制all-one寄存器.这甚至不在现代CPU上使用执行单元(但仍然需要前端问题带宽).但是,如果你没有向量寄存器,加载常量或是vinsertf128很好的选择.
对于AVX512,值得尝试vxorps或者也许vcmptrueps.每个只有1c吞吐量,但它们应该打破对zmm0旧值的依赖(不像vpcmpeqd).它们需要一个掩码或整数寄存器,您可以使用vxorps或在循环外部初始化它们vcmptrueps.
对于AVX512掩码寄存器,vbroadcastss可以工作,但它不依赖于当前CPU的依赖性. 英特尔的优化手册建议在收集指令之前使用它来生成全1,但建议避免使用与输出相同的输入寄存器.这避免了在循环中依赖于前一个的独立集合.由于k0经常使用,通常是一个很好的选择.
我认为vpternlogd zmm0,zmm0,zmm0, 0xff会起作用,但它可能不是特殊的,因为k0 = 1成语而不依赖于zmm0.(要设置所有64位而不是低16位,请使用AVX512BW 1)
在Skylake-AVX512上,vmov*对掩码寄存器进行操作的指令只能在单个端口上运行,即使是简单的端口也是如此[v]pcmpeq[b/w/d].(另请注意,当管道中有任何512b操作时,Skylake-AVX512将不会在port1上运行向量uop,因此执行单元吞吐量可能是一个真正的瓶颈.)
没有VPMOVM2D zmm0, k0,只从整数或内存移动.可能没有VPBROADCASTD zmm0, eax相同的指令,同样被检测为特殊指令,因此发出/重命名阶段的硬件不会为vpternlogd寄存器寻找它.
| 归档时间: |
|
| 查看次数: |
2154 次 |
| 最近记录: |