2016-02-29 2 views
5

Вот некоторые довольно простой код, составленный с -O2 (GCC 4.8.5):что останавливает GCC __restrict__ спецификатор от работы

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; 
} 

и вот соответствующая сборка:

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 

Когда скомпилированный без ограничителя, выход идентичен: Множество смешанных нагрузок и хранения. Некоторое значение загружается дважды, и похоже, что никакой оптимизации не произошло. Если pix и line являются unaliased, я ожидаю, что компилятор будет достаточно умным, и среди прочего загрузите pix [1] и pix [3] только один раз.

Вы знаете что-нибудь, что может дисквалифицировать квалификатор restrict?

PS: С новой версией gcc (4.9.2), на другой архитектуре (рука v7), результат схож. Вот тестовый скрипт для сравнения сгенерированного кода с ограничением и без него.

#!/bin/sh 
gcc -c -o test.o -std=c99 -O2 yuyv_to_jpegycbcr.c 
objdump -d test.o > test.S 


gcc -c -o test2.o -O2 -D restrict='' yuyv_to_jpegycbcr.c 
objdump -d test2.o > test2.S 
+0

По какой-либо причине вы не используете стандартный «ограничитель»? – Olaf

+0

, потому что использование std = c99 разбивает мой код, возможно, потому, что я не установил допустимый feature_test_macros. Я могу это исправить, но я не думаю, что это изменило бы ситуацию. – shodanex

+0

Здесь также следует ожидать векторизации (при условии, что устройство, которое вы компилируете для его поддержки). – marko

ответ

4

Положить ограничение на параметры функции, а не на локальные переменные.

Из моего опыта большинство компиляторов (включая GCC) используют ограничение только в том случае, если оно указано в параметрах функции. Все использования локальных переменных внутри функции игнорируются.

Я подозреваю, что это связано с анализом сглаживания, выполняемым на уровне функции, а не на уровне базового блока. Но у меня нет никаких доказательств, чтобы поддержать это. Кроме того, он, вероятно, зависит от версии компилятора и компилятора.

В любом случае, подобные вещи довольно тонкие, чтобы полагаться на них. Поэтому, если производительность имеет значение, либо вы оптимизируете ее вручную, либо не забываете пересматривать ее каждый раз при обновлении или изменении компиляторов.

+1

За комментарий к https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60712 кажется, что gcc применяет ограничение только к параметру функции – shodanex

+0

Я вижу именно это с умножением на матричную матрицу. У этого есть шесть петель. Если я поставил самые внутренние три петли в статическую функцию с ограниченными параметрами, тогда код будет в два раза быстрее, чем если бы я не объявлял функцию. Я вижу тот же эффект с GCC (6.3) и Clang (4.0). Таким образом, кажется, что компиляторы игнорируют локальные переменные с ограничением, как вы говорите. Я не знаю о ICC. –

+0

И даже иногда, когда я объявляю отдельную статическую функцию, компилятор дает худший результат. Иногда мне приходится объявлять внутреннюю функцию с ограничением в отдельном объектном файле. Поэтому вы должны делать именно то, что вы говорите: сначала проверьте сборку, и каждое обновление или компилятор изменится. –

Смежные вопросы