内部__lzcnt64使用不同的编译选项返回不同的值

我有以下代码:

#include  #include  #include  long long lzcnt(long long l) { return __lzcnt64(l); } int main(int argc, char** argv) { printf("%lld\n", lzcnt(atoll(argv[1]))); return 0; } 

使用不同的编译器和选项运行(显示程序集):

 $ clang -Wall src/test.c -D__LZCNT__ && ./a.out 2047 53 0000000000400560 : 400560: 55 push %rbp 400561: 48 89 e5 mov %rsp,%rbp 400564: 48 89 7d f0 mov %rdi,-0x10(%rbp) 400568: 48 8b 7d f0 mov -0x10(%rbp),%rdi 40056c: 48 89 7d f8 mov %rdi,-0x8(%rbp) 400570: 48 8b 7d f8 mov -0x8(%rbp),%rdi 400574: 48 0f bd ff bsr %rdi,%rdi 400578: 48 83 f7 3f xor $0x3f,%rdi 40057c: 89 f8 mov %edi,%eax 40057e: 48 63 c0 movslq %eax,%rax 400581: 5d pop %rbp 400582: c3 retq 400583: 66 66 66 66 2e 0f 1f data32 data32 data32 nopw %cs:0x0(%rax,%rax,1) 40058a: 84 00 00 00 00 00 

没有-mlzcnt的GCC

 $ gcc -Wall src/test.c -D__LZCNT__ && ./a.out 2047 53 0000000000400580 : 400580: 55 push %rbp 400581: 48 89 e5 mov %rsp,%rbp 400584: 48 89 7d e8 mov %rdi,-0x18(%rbp) 400588: 48 8b 45 e8 mov -0x18(%rbp),%rax 40058c: 48 89 45 f8 mov %rax,-0x8(%rbp) 400590: 48 0f bd 45 f8 bsr -0x8(%rbp),%rax 400595: 48 83 f0 3f xor $0x3f,%rax 400599: 48 98 cltq 40059b: 5d pop %rbp 40059c: c3 retq 

GCC与-mlzcnt

 $ gcc -Wall src/test.c -D__LZCNT__ -mlzcnt && ./a.out 2047 10 0000000000400580 : 400580: 55 push %rbp 400581: 48 89 e5 mov %rsp,%rbp 400584: 48 89 7d e8 mov %rdi,-0x18(%rbp) 400588: 48 8b 45 e8 mov -0x18(%rbp),%rax 40058c: 48 89 45 f8 mov %rax,-0x8(%rbp) 400590: f3 48 0f bd 45 f8 lzcnt -0x8(%rbp),%rax 400596: 48 98 cltq 400598: 5d pop %rbp 400599: c3 retq 

没有-mlzcnt的G ++

 $ g++ -Wall src/test.c -D__LZCNT__ && ./a.out 2047 In file included from /usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/immintrin.h:64:0, from /usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/x86intrin.h:62, from src/test.c:3: /usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/lzcntintrin.h: In function 'short unsigned int __lzcnt16(short unsigned int)': /usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/lzcntintrin.h:38:29: error: '__builtin_clzs' was not declared in this scope return __builtin_clzs (__X); 

G ++与-mlzcnt

 $ g++ -Wall src/test.c -D__LZCNT__ -mlzcnt && ./a.out 2047 10 0000000000400640 : 400640: 55 push %rbp 400641: 48 89 e5 mov %rsp,%rbp 400644: 48 89 7d e8 mov %rdi,-0x18(%rbp) 400648: 48 8b 45 e8 mov -0x18(%rbp),%rax 40064c: 48 89 45 f8 mov %rax,-0x8(%rbp) 400650: f3 48 0f bd 45 f8 lzcnt -0x8(%rbp),%rax 400656: 48 98 cltq 400658: 5d pop %rbp 400659: c3 retq 

区别在于-mlzcnt的使用很明显,但是我实际上是在C ++中工作而没有那个选项它不能在g ++上编译(clang ++很好)。 看起来当使用-mlzcnt时,结果是63-(没有-mlzct的结果)。 是否有关于gcc的-mlzcnt选项的任何文档(我查看了信息文件,但找不到任何内容)? 是否有更多选择lzcnt指令的东西?

首先,我能够用clang 3.3和gcc 4.8.1完美地复制你的问题。

这是我的想法……我只有50%左右。

  • LZCNT是您的计算机可能不支持的指令。
  • 维基百科建议LZCNT需要Haswell支持
  • 我们可以尝试使用Linux应用程序cpuid来validation此信息。 (包含在Debian,RHEL等中)。
  • 维基百科再次建议“通过CPUID.80000001H:ECX.ABM [Bit 5]标志”指示“支持”。

让我们来看看我的系统(Xeon X3430,Lynnfield,Nehalem)。

 [4:48pm][wlynch@apple /tmp] sudo cpuid -1ir | grep 80000001 0x80000001 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000001 edx=0x28100800 

因此,ECX的第23位不是真的。 所以我的系统不支持LZCNT。

看起来我的机器将不支持的LZCNT解释为BSR。

您似乎在调用__lzcnt64但传递32位整数。 也许这让编译器感到困惑。

可能那个返回10的人在寄存器的另一半看到了一些垃圾?

试试这个:

  long long int v = __lzcnt64(2047LL); 

(做了long long文字)。