2016-02-29 18 views
5

Oto dość prosty kod, skompilowany z -O2 (gcc 4.8.5):co zatrzymuje GCC __restrict__ kwalifikator z pracy

unsigned char * linebuf; 
int yuyv_tojpegycbcr(unsigned char * buf, int w) 
{ 
    int col; 
    unsigned char * restrict pix = buf; 
    unsigned char * restrict line = linebuf; 

    for(col = 0; col < w - 1; col +=2) 
    { 
      line[col*3] = pix[0]; 
      line[col*3 + 1] = pix[1]; 
      line[col*3 + 2] = pix[3]; 
      line[col*3 + 3] = pix[2]; 
      line[col*3 + 4] = pix[1]; 
      line[col*3 + 5] = pix[3]; 
      pix += 4; 
    } 
    return 0; 
} 

i tutaj jest odpowiedni montaż:

0000000000000000 <yuyv_tojpegycbcr>: 
    0: 83 fe 01    cmp $0x1,%esi 
    3: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax  # a <yuyv_tojpegycbcr+0xa> 
    a: 7e 4e     jle 5a <yuyv_tojpegycbcr+0x5a> 
    c: 83 ee 02    sub $0x2,%esi 
    f: 31 d2     xor %edx,%edx 
    11: d1 ee     shr %esi 
    13: 48 8d 74 76 03   lea 0x3(%rsi,%rsi,2),%rsi 
    18: 48 01 f6    add %rsi,%rsi 
    1b: 0f 1f 44 00 00   nopl 0x0(%rax,%rax,1) 
    20: 0f b6 0f    movzbl (%rdi),%ecx 
    23: 48 83 c2 06    add $0x6,%rdx 
    27: 48 83 c7 04    add $0x4,%rdi 
    2b: 48 83 c0 06    add $0x6,%rax 
    2f: 88 48 fa    mov %cl,-0x6(%rax) 
    32: 0f b6 4f fd    movzbl -0x3(%rdi),%ecx 
    36: 88 48 fb    mov %cl,-0x5(%rax) 
    39: 0f b6 4f ff    movzbl -0x1(%rdi),%ecx 
    3d: 88 48 fc    mov %cl,-0x4(%rax) 
    40: 0f b6 4f fe    movzbl -0x2(%rdi),%ecx 
    44: 88 48 fd    mov %cl,-0x3(%rax) 
    47: 0f b6 4f fd    movzbl -0x3(%rdi),%ecx 
    4b: 88 48 fe    mov %cl,-0x2(%rax) 
    4e: 0f b6 4f ff    movzbl -0x1(%rdi),%ecx 
    52: 88 48 ff    mov %cl,-0x1(%rax) 
    55: 48 39 f2    cmp %rsi,%rdx 
    58: 75 c6     jne 20 <yuyv_tojpegycbcr+0x20> 
    5a: 31 c0     xor %eax,%eax 
    5c: c3      retq 

Kiedy skompilowany bez kwalifikatora ograniczenia, dane wyjściowe są identyczne: Wiele wymieszanych ładunków i sklepów. Niektóre wartości są ładowane dwa razy i wygląda na to, że nie nastąpiła żadna optymalizacja. Jeśli wartości nie są zgodne z wersją pix i line, oczekuję, że kompilator będzie wystarczająco inteligentny i między innymi ładuje pix [1] i pix [3] tylko raz.

Czy znasz coś, co może zdyskwalifikować kwalifikator restrict?

PS: Z nowszym gcc (4.9.2), na innej architekturze (ramię v7), wynik jest podobny. Oto skrypt testowy do porównywania wygenerowanego kodu zi bez ograniczeń.

+0

Jakiś powód, dla którego nie używasz standardowego kwalifikatora 'ograniczającego'? – Olaf

+0

ponieważ użycie std = c99 powoduje przerwanie mojego kodu, prawdopodobnie dlatego, że nie ustawiłem poprawnego parametru feature_test_macros. Mogę to naprawić, ale nie sądzę, żeby to miało jakiś wpływ. – shodanex

+0

Powinieneś się także spodziewać wektoryzacji (zakładając, że urządzenie, które kompilujesz, obsługuje je). – marko

Odpowiedz

4

Ogranicza raczej parametry funkcji niż zmienne lokalne.

Z mojego doświadczenia wynika, że ​​większość kompilatorów (w tym GCC) wykorzystuje ograniczenie tylko wtedy, gdy jest określone w parametrach funkcji. Wszystkie zastosowania zmiennych lokalnych w funkcji są ignorowane.

Podejrzewam, że ma to związek z analizą aliasingu wykonywaną na poziomie funkcji, a nie na poziomie bloku podstawowego. Ale nie mam żadnych dowodów na poparcie tego. Co więcej, prawdopodobnie różni się w zależności od wersji kompilatora i kompilatora.

Tak czy inaczej, te rodzaje rzeczy są dość wybredne, na których można polegać. Jeśli więc wydajność ma znaczenie, albo zoptymalizuj ją ręcznie, albo pamiętaj, aby ją powtórzyć za każdym razem, gdy uaktualnisz lub zmienisz kompilatory.

+1

Za komentarz do https://gc.gnu.org/bugzilla/show_bug.cgi?id=60712, wydaje się, że gcc stosuje się tylko do parametru funkcji – shodanex

+0

Widzę to dokładnie z mnożeniem macierzy bloków. Ma sześć pętli. Jeśli umieściłem najgłębsze trzy pętle w funkcji statycznej z ograniczonymi parametrami, kod będzie dwa razy szybszy, niż gdybym nie deklarował funkcji. Widzę ten sam efekt z GCC (6.3) i Clang (4.0). Wygląda więc na to, że kompilatory ignorują zmienne lokalne z ograniczeniem dokładnie tak, jak mówisz. Nie wiem o ICC. –

+0

Nawet gdy deklaruję oddzielną funkcję statyczną, kompilator daje gorszy wynik. Czasami muszę zadeklarować wewnętrzną funkcję z ograniczeniem w oddzielnym pliku obiektu. Więc musisz zrobić dokładnie to, co mówisz: sprawdź zestaw po raz pierwszy i każdą aktualizację lub zmianę kompilatora. –