2012-02-19 17 views
14

Jaka jest implementacja GCC (4.6+) __builtin_clz? Czy odpowiada niektórym instrukcjom procesora w Intel x86_64 (AVX)?Implementacja __builtin_clz

+2

Czy spróbować? –

+0

Nie wiem, ale jeśli jest dostępny, "LZCNT" wydaje się być prawdopodobnym kandydatem. (Patrz http://en.wikipedia.org/wiki/SSE4) – reuben

Odpowiedz

14

Należy przetłumaczyć na instrukcję Bit Scan Reverse i odjąć. BSR podaje indeks wiodącego 1, a następnie można go odjąć od rozmiaru słowa, aby uzyskać liczbę zer wiodących.

Edycja: jeśli twój procesor obsługuje LZCNT (Leading Zero Count), to prawdopodobnie zrobi to samo, ale nie wszystkie układy x86-64 mają tę instrukcję.

2

Tak, odpowiada instrukcji procesora BSR (skanowanie bitowe do tyłu).

Oto przykładowy kod, który może pomóc:

int a=20; //10100 

//trailing zeroes 
cout<<__builtin_ctz(a)<<endl; //gives 2 
cout<<__builtin_ctz(a<<4)<<endl; //gives 6 

//leading zeroes 
cout<<__builtin_clz(a)<<endl; //gives 27 
cout<<__builtin_clz(a>>4)<<endl; //gives 31 

cout<<__builtin_clz(0)<<endl; //gives 32 
+1

To źle. Odpowiada to bsr i odejmowaniu. Również przykład nie dodaje nic do roszczenia. A także, pytanie jest wyraźnie oznaczone jako C i wymieniono konkretny kompilator (gcc). Przykładowy kod nie działa. – hroptatyr

11

Tak i nie.

CLZ (zerem wiodącym zliczającym) i BSR (odwrócony bit-skan) są powiązane, ale różne. CLZ jest równy (wpisz bitową szerokość mniejszą) - BSR. CTZ (zliczanie zliczające zera), znane również jako FFS (pierwszy znaleziony zestaw) jest taki sam, jak z BSF (skanowanie w kierunku bitu do przodu).

Należy pamiętać, że wszystkie te parametry są nieokreślone przy zerowej pracy!

W odpowiedzi na twoje pytanie, przez większość czasu na x86 i x86_64, __builtin_clz generuje operację BSR odejmowaną od 31 (lub niezależnie od szerokości twojego typu), a __builting_ctz generuje operację BSF.

Jeśli chcesz wiedzieć, co generuje GIGA asembler, najlepiej wiedzieć, jak to sprawdzić. Flaga -S będzie miał wyświetlamy GCC asembler to wygenerowany dla danego wejścia:

gcc -S -o test.S test.c

Rozważmy:

unsigned int clz(unsigned int num) { 
    return __builtin_clz(num); 
} 

unsigned int ctz(unsigned int num) { 
    return __builtin_ctz(num); 
} 

On x 86 do CLZ gcc (-O2) generuje:

bsrl %edi, %eax 
xorl $31, %eax 
ret 

i CTZ:

bsfl %edi, %eax 
ret 

Pamiętaj, że jeśli naprawdę chcesz bsr, a nie clz, musisz zrobić 31 - clz (dla 32-bitowych liczb całkowitych). To wyjaśnia XOR 31, jako x XOR 31 == 31 - x (to tożsamość jest prawdziwe tylko dla liczb od od 2^r - 1) Więc:

num = __builtin_clz(num)^31; 

daje

bsrl %edi, %eax 
ret