问题描述
我在 Intel 内在函数指南中看到,您可以使用 vpcmpb
而无需立即实现相等比较的效果:https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=AVX_512&expand=6816,914&text=vpcmpb
我尝试编写以下汇编指令:vpcmpb %zmm30,%zmm0,%k1
(g++ 语法),比较相等的 zmm30
和 zmm0
,将结果写入 k1
。但是,汇编程序会抱怨操作数的数量错误。这是怎么回事?
解决方法
有 3 个有效的机器操作码可以执行此操作:
-
vpcmpeqb k,zmm,zmm
(EVEX form of the MMX/SSE2/AVX266 0F 74
opcode 代表[v]pcmpeq [xy]mm,[xy]mm
。这些从来没有立即生效,只有eq
和签名的gt
谓词可用作不同的操作码) -
vpcmpb
orvpcmpub
直接0
(只有 EVEX 形式的新说明,EVEX.512.66.0F3A.W0 3F
或3E
)。
在 asm source 中,汇编程序允许您使用 vpcmpleb k,zmm
作为编写 vpcmpb k,z,2
的更有意义的方式,如 Intel's vol. 2 说明书。即将谓词作为助记词的一部分,暗示直接。
该表包含一行 VPCMPEQ* reg1,reg2,reg3
-> VPCMP* reg1,reg3,0
,但在实际汇编程序中,较短的非直接形式优先于 vpcmpeqb k,zmm
。
NASM 源与 objdump -S -drwC -Mintel
反汇编混合。 (使用gas .intel_syntax noprefix
组装的结果相同):
vpcmpeqb k1,zmm0,zmm1
0: 62 f1 7d 48 74 c9 vpcmpeqb k1,zmm1 # 74 opcode
vpcmpb k1,zmm1,0
6: 62 f3 7d 48 3f c9 00 vpcmpeqb k1,zmm1 # 3f opcode
vpcmpequb k1,zmm1
d: 62 f3 7d 48 3e c9 00 vpcmpequb k1,zmm1 # 3e opcode
vpcmpub k1,0
14: 62 f3 7d 48 3e c9 00 vpcmpequb k1,zmm1 # 3e opcode
有趣的是,NASM/GAS 会按照书面形式将 vpcmpb k1,0
组合成带有立即数的形式。但是 objdump
会将其反汇编回 vpcmpeqb k1,zmm1
,与非立即操作码相同,因此这是反汇编/重新组装往返会更改机器代码的情况之一。 (当然不是指令的架构效果)
NASM / GAS 不会为您将 vpcmpequb
优化为 vpcmpeqb
,因此在比较整数相等性时始终避免使用无符号版本。
内在指南中的错误
如果您使用 asm 编写,请查看 asm 参考手册(HTML 摘录 Table 5-17 或从中抓取的英特尔原始 PDF),而不是 Intrinsics 指南。尤其是当您在某些内容与工具和/或 CPU 似乎在做什么之间遇到任何谜团或分歧时!
众所周知,内在指南肯定有错误(尽管当人们在英特尔论坛上报告它们时,它们确实得到了修复)。尤其可能会在对使用 C/C++ 内在函数的正确性不重要的部分中看到错误。
Intel 的 asm 手册也有错误,但也不是没有什么比为已经发布的指令集遗漏整个机器操作码形式的指令更严重的错误。
如果没有明确的直接、真实的 asm 源代码或机器代码的描述,vpcmpb k,zmm
永远不会有效,所以是的,这绝对是内在指南中的错误。
带有反向操作数列表和 vpcmpeqb %zmm,%zmm,%k
的 $immediate
asm 语法是“AT&T 语法”。它恰好是 GAS 默认用于 .s
/ .S
文件的一种,但您可以使用 .intel_syntax noprefix
。
将内联 asm 用于单个指令通常没有意义 - 编译器通常可以很好地处理内在函数,尽管对于 AVX-512 掩码内容可能并不总是如此。