14

使用 c 程序:

int main(int argc , char** argv)
{

  return  __builtin_popcountll(0xf0f0f0f0f0f0f0f0);

}

和编译器行(gcc 4.4 - Intel Xeon L3426):

gcc -msse4.2 poptest.c -o poptest

我没有得到内置的 popcnt 指令,而是编译器生成一个查找表并以这种方式计算 popcount。生成的二进制文件超过 8000 字节。(哎呀!)

非常感谢您的帮助。

4

3 回答 3

26

您必须告诉 GCC 为支持 popcnt 指令的体系结构生成代码:

gcc -march=corei7 popcnt.c

或者只是启用对 popcnt 的支持:

gcc -mpopcnt popcnt.c

在您的示例程序中,参数 to__builtin_popcountll是一个常量,因此编译器可能会在编译时进行计算,并且永远不会发出 popcnt 指令。即使没有要求优化程序,GCC 也会这样做。

所以尝试传递一些它在编译时不知道的东西:

int main (int argc, char** argv)
{
    return  __builtin_popcountll ((long long) argv);
}

$ gcc -march=corei7 -O popcnt.c && objdump -d a.out | grep '<main>' -A 2
0000000000400454 <main>:
  400454:       f3 48 0f b8 c6          popcnt %rsi,%rax
  400459:       c3                      retq
于 2012-11-03T18:10:23.270 回答
4

你需要这样做:

#include <stdio.h>
#include <smmintrin.h>

int main(void)
{
    int pop = _mm_popcnt_u64(0xf0f0f0f0f0f0f0f0ULL);
    printf("pop = %d\n", pop);
    return 0;
}

$ gcc -Wall -m64 -msse4.2 popcnt.c -o popcnt
$ ./popcnt 
pop = 32
$ 

编辑

糟糕——我刚刚用 gcc 4.2 和 ICC 11.1 检查了反汇编输出——而 ICC 11.1 正确生成popcntlor popcntq,由于某种原因 gcc 没有——它___popcountdi2改为调用。诡异的。当我有机会时,我会尝试更新版本的 gcc,看看它是否已修复。我想唯一的解决方法是使用 ICC 而不是 gcc。

于 2011-06-21T15:27:37.490 回答
2

对于__builtin_popcountll在 GCC 中,您需要做的就是添加-mpopcnt

#include <stdlib.h>
int main(int argc, char **argv) {
    return __builtin_popcountll(atoi(argv[1]));
}

-mpopcnt

$ otool -tvV a.out
a.out:
(__TEXT,__text) section
_main:
0000000100000f66    pushq   %rbp
0000000100000f67    movq    %rsp, %rbp
0000000100000f6a    subq    $0x10, %rsp
0000000100000f6e    movq    %rdi, -0x8(%rbp)
0000000100000f72    movq    -0x8(%rbp), %rax
0000000100000f76    addq    $0x8, %rax
0000000100000f7a    movq    (%rax), %rax
0000000100000f7d    movq    %rax, %rdi
0000000100000f80    callq   0x100000f8e ## symbol stub for: _atoi
0000000100000f85    cltq
0000000100000f87    popcntq %rax, %rax
0000000100000f8c    leave
0000000100000f8d    retq

没有-mpopcnt

a.out:
(__TEXT,__text) section
_main:
0000000100000f55    pushq   %rbp
0000000100000f56    movq    %rsp, %rbp
0000000100000f59    subq    $0x10, %rsp
0000000100000f5d    movq    %rdi, -0x8(%rbp)
0000000100000f61    movq    -0x8(%rbp), %rax
0000000100000f65    addq    $0x8, %rax
0000000100000f69    movq    (%rax), %rax
0000000100000f6c    movq    %rax, %rdi
0000000100000f6f    callq   0x100000f86 ## symbol stub for: _atoi
0000000100000f74    cltq
0000000100000f76    movq    %rax, %rdi
0000000100000f79    callq   0x100000f80 ## symbol stub for: ___popcountdi2
0000000100000f7e    leave
0000000100000f7f    retq

笔记

在使用 POPCNTQ 之前,请务必检查 CPUID 功能位的 ABM 位(位 23)

于 2016-09-15T02:37:12.473 回答