我正在运行Core i7 3930k,这是Sandy Bridge微体系结构。 执行以下代码(在MSVC19,VS2015下编译)时,结果让我感到惊讶(参见评论):
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
说明,但我想知道这种情况有多常见。
答案 0 :(得分:3)
Sandy Bridge(及更早版本)处理器似乎支持app.js:32946 Uncaught ReferenceError: BarcodesPOSearch is not defined
at HTMLButtonElement.<anonymous> (app.js:32946)
at HTMLDocument.dispatch (app.js:23180)
at HTMLDocument.elemData.handle (app.js:22988)
和lzcnt
的原因是这两个指令都具有向后兼容的编码。
tzcnt
在较旧的处理器上,只会忽略lzcnt eax,eax = rep bsr eax,eax
tzcnt eax,eax = rep bsf eax,eax
前缀。
这个好消息太多了 坏消息是两个版本的语义都不同。
rep
当来源&lt;&gt;时,至少lzcnt eax,zero => eax = 32, CF=1, ZF=0
bsr eax,zero => eax = undefined, ZF=1
lzcnt eax,0xFFFFFFFF => eax=0, CF=0, ZF=1 //dest=number of msb leading zeros
bsr eax,0xFFFFFFFF => eax=31, ZF=0 //dest = bit index of highest set bit
tzcnt eax,zero => eax = 32, CF=1, ZF=0
bsf eax,zero => eax = undefined, ZF=1
tzcnt eax,0xFFFFFFFF => eax=0, CF=0, ZF=1 //dest=number of lsb trailing zeros
bsf eax,0xFFFFFFFF => eax=0, ZF=0 //dest = bit index of lowest set bit
和bsf
会生成相同的输出0. tzcnt
和bsr
不同意
lzcnt
和lzcnt
的执行速度也比tzcnt
/ bsr
快得多
完全糟糕的是bsf
和bsf
无法就标志使用情况达成一致。
这种不必要的不一致意味着我不能使用tzcnt
作为tzcnt
的替代品,除非我能确定其来源是非零的。