2015-10-08 2 views
0

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

Например, с векторизации, я узнал, что вы можете избежать множества дополнительных сборочных линий, предоставив дополнительную информацию GCC о выравнивании массива. http://locklessinc.com/articles/vectorize/

Вот мой эксперимент.

#define SIZE 1024 
void itwillwork (const uint16_t * a, const uint16_t * b, uint16_t * comp) { 
    int i = 0; 
    comp[i]=a[i]|b[i]; 
} 

Формирует простой монтаж:

.globl _ZN8Test_LUT7performEv 
    23    _ZN8Test_LUT7performEv: 
    24    .LFB664: 
    25     .cfi_startproc 
    26 0020 488B4710  movq 16(%rdi), %rax 
    27 0024 488B4F08  movq 8(%rdi), %rcx 
    28 0028 488B5720  movq 32(%rdi), %rdx 
    29 002c 0FB700  movzwl (%rax), %eax 
    30 002f 660B01  orw (%rcx), %ax 
    31 0032 668902  movw %ax, (%rdx) 
    32 0035 C3   ret 
    33     .cfi_endproc 

Но, даже если я ожидал несколько дополнительных линий, я очень удивлен тем, что я получил после добавления петли:

#define SIZE 1024 
void itwillwork (const uint16_t * a, const uint16_t * b, uint16_t * comp) { 
    int i = 0; 
    for(i=0;i<SIZE;i++) 
     comp[i]=a[i]|b[i]; 
} 

Генерирует эту сборку с гораздо большим количеством линий:

233    _Z10itwillworkPKtS0_Pt: 
234    .LFB663: 
235     .cfi_startproc 
236 0250 488D4210  leaq 16(%rdx), %rax 
237 0254 488D4E10  leaq 16(%rsi), %rcx 
238 0258 4839F0  cmpq %rsi, %rax 
239 025b 410F96C0  setbe %r8b 
240 025f 4839CA  cmpq %rcx, %rdx 
241 0262 0F93C1  setnb %cl 
242 0265 4108C8  orb %cl, %r8b 
243 0268 743E   je .L55 
244 026a 4839F8  cmpq %rdi, %rax 
245 026d 488D4710  leaq 16(%rdi), %rax 
246 0271 0F96C1  setbe %cl 
247 0274 4839C2  cmpq %rax, %rdx 
248 0277 0F93C0  setnb %al 
249 027a 08C1   orb %al, %cl 
250 027c 742A   je .L55 
251 027e 31C0   xorl %eax, %eax 
252     .p2align 4,,10 
253     .p2align 3 
254    .L57: 
255 0280 F30F6F0C  movdqu (%rsi,%rax), %xmm1 
255  06 
256 0285 F30F6F04  movdqu (%rdi,%rax), %xmm0 
256  07 
257 028a 660FEBC1  por %xmm1, %xmm0 
258 028e F30F7F04  movdqu %xmm0, (%rdx,%rax) 
258  02 
259 0293 4883C010  addq $16, %rax 
260 0297 483D0008  cmpq $2048, %rax 
260  0000 
261 029d 75E1   jne .L57 
262 029f F3C3   rep ret 
263     .p2align 4,,10 
264 02a1 0F1F8000  .p2align 3 
264  000000 
265    .L55: 
266 02a8 31C0   xorl %eax, %eax 
267 02aa 660F1F44  .p2align 4,,10 
267  0000 
268     .p2align 3 
269    .L58: 
270 02b0 0FB70C06  movzwl (%rsi,%rax), %ecx 
271 02b4 660B0C07  orw (%rdi,%rax), %cx 
272 02b8 66890C02  movw %cx, (%rdx,%rax) 
273 02bc 4883C002  addq $2, %rax 
274 02c0 483D0008  cmpq $2048, %rax 
274  0000 
275 02c6 75E8   jne .L58 
276 02c8 F3C3   rep ret 
277     .cfi_endproc 

Оба были скомпилированы с gcc 4.8.4 в режиме освобождения, -O2 -ftree-vectorize -msse2.

Может ли кто-нибудь помочь мне избавиться от этих линий? Или, если это невозможно, можете ли вы сказать мне, почему они там?

Update:

Я пробовал трюки там http://locklessinc.com/articles/vectorize/, но я получаю еще один вопрос:

#define SIZE 1024 
void itwillwork (const uint16_t * a, const uint16_t * b, uint16_t * comp) { 
    int i = 0; 
    for(i=0;i<SIZE;i++) 
     comp[i]=a[i]|b[i]; 
} 

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

itwillwork(a,b,c); 

Там нет инструкции вызова: длинный список инструкций «itwillwork» (то же самое, что и выше) используются непосредственно. Я что-то упустил? («Лишние линии» является проблемой, а не встроенный вызов)

+1

Приятная идея - вставить код сборки в свой вопрос, вместо того, чтобы перейти на сайт pastebin.Я не понимаю, почему вы ставите код высокого уровня в свой вопрос, но не сборку. –

+4

Почему вы думаете, что у вас так много других строк - это плохо? Если оптимизированный код работает быстро, вам небезразличен размер кода? Но также, ЧТО вы пробовали с 'ограничить' (вывести эту версию кода на C++). Код asm выглядит так, как будто компилятор не знает о указателях ограничений (особенно 'comp') и был бы более эффективным, если бы это было так. – JSF

+0

Я попытался вставить здесь код сборки, но он вообще не читался (по какой-то причине нет строки). – Utundu

ответ

1

Вы получаете «странно» кода, потому что GCC не может делать предположения относительно выравнивания ваших указателей, так что вы можете увидеть, что он первый выполняет выравнивание чтобы определить, может ли он пройти быстрый путь и выполнять 128 бит за раз, или медленный путь и делать по 16 бит за раз.

Кроме того, причина, по которой вы находите повторяющийся код, заключается в том, что компилятор применяет оптимизацию наложения. Вы можете отключить это с помощью спецификации __attribute((noinline)), но если производительность - ваша цель, пусть компилятор включит ее.

Если указать __restrict ключевое слово, то компилятор будет генерировать только код быстрого пути: https://goo.gl/g3jUfQ

Однако, это не означает, что компилятор будет волшебно заботиться о выравнивании для вас, чтобы заботиться о том, что вы передаете функции.

+0

Я пробовал это, он работал хорошо, спасибо! Тем не менее, я пробовал использовать класс (теперь переменные атрибуты и функции теперь являются методами, см. Https://goo.gl/x7aP6W - код не должен делать ничего интересного). Как вы можете видеть, это скомпилировано «правильно». Но как только я разбил этот код на файлы «.h» и «.cpp», я получаю дополнительные строки, упомянутые ранее. Любая идея почему? – Utundu

+0

Как выглядит прототип и определение. – Olipro

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