Как сгенерировать машинную инструкцию для sse4.2 popcnt - PullRequest
12 голосов
/ 21 июня 2011

Используя программу 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, скорее компиляторгенерирует таблицу поиска и таким образом вычисляет количество пользователей.Полученный двоичный файл имеет размер более 8000 байт.(Юк!)

Большое спасибо за любую помощь.

Ответы [ 3 ]

25 голосов
/ 03 ноября 2012

Вы должны указать GCC генерировать код для архитектуры, которая поддерживает инструкция popcnt:

gcc -march=corei7 popcnt.c

Или просто включите поддержку popcnt:

gcc -mpopcnt popcnt.c

В вашем примере программы параметр __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
4 голосов
/ 21 июня 2011

Вам нужно сделать это так:

#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 - пока ICC11.1 правильно генерирует popcntl или popcntq, по какой-то причине gcc этого не делает - вместо этого он вызывает ___popcountdi2.Weird.Я попробую более новую версию gcc, когда у меня будет шанс, и посмотрю, исправлена ​​ли она.Я думаю, что единственный способ обойти это - использовать ICC вместо gcc.

1 голос
/ 15 сентября 2016

Для __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

обязательно проверьте бит ABM (бит 23) функциональных битов CPUID.
...