【发布时间】:2017-05-09 21:34:28
【问题描述】:
我正在运行属于 Sandy Bridge 微架构的 Core i7 3930k。 执行以下代码时(在MSVC19、VS2015下编译),结果让我吃惊(见cmets):
int wmain(int argc, wchar_t* argv[])
{
uint64_t r = 0b1110'0000'0000'0000ULL;
uint64_t tzcnt = _tzcnt_u64(r);
cout << tzcnt << endl; // prints 13
int info[4]{};
__cpuidex(info, 7, 0);
int ebx = info[1];
cout << bitset<32>(ebx) << endl; // prints 32 zeros (including the bmi1 bit)
return 0;
}
反汇编表明tzcnt指令确实是从内在发出的:
uint64_t r = 0b1110'0000'0000'0000ULL;
00007FF64B44877F 48 C7 45 08 00 E0 00 00 mov qword ptr [r],0E000h
uint64_t tzcnt = _tzcnt_u64(r);
00007FF64B448787 F3 48 0F BC 45 08 tzcnt rax,qword ptr [r]
00007FF64B44878D 48 89 45 28 mov qword ptr [tzcnt],rax
为什么我没有收到#UD 无效操作码异常,指令运行正常,CPU 报告它不支持上述指令?
这可能是一些奇怪的微代码修订版,其中包含指令的实现但不报告对它的支持(以及 bmi1 中包含的其他内容)?
我还没有检查过bmi1 的其余说明,但我想知道这种现象有多普遍。
【问题讨论】:
-
来自Instruction Set Reference:LZCNT 与 BSR 不同。例如,当输入操作数为零时,LZCNT 将产生操作数大小。 需要注意的是,在不支持LZCNT的处理器上,指令字节编码是作为BSR执行的。
-
@Michael Petch 你写了错误的指令,但你写的似乎也适用于
TZCNT和BSF。 -
是的,抱歉,我很快扫了一眼这个问题。正如您所发现的,同样的事情适用于 TZCNT 和 BSF。
-
“好”消息是对于定义了
bsf的所有值,tzcnt至少与bsf一致。它们仅在零输入的行为上有所不同,其中bsf未定义,tzcnt返回 32 或 64(分别针对 32 位或 64 位输入)。手上的lzcnt返回完全不同的结果(本质上是31 - bsr)。