我正在进行矢量化循环,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。
有人可以帮我摆脱那些台词吗?或者,如果不可能,你能告诉我他们为什么在那里吗?
更新:
我已经尝试了那里的技巧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);
没有通话指令:&#34; itwillwork&#34; (与上面相同)直接使用。 我错过了什么吗? (&#34;额外的行&#34;是问题,而不是内联呼叫)
答案 0 :(得分:1)
你得到“怪异的”代码,因为GCC不能对指针的对齐做出假设,所以你可以看到它首先执行对齐测试来确定它是否可以采用快速路径和一次做128位,或慢速做一次16位。
此外,您发现重复代码的原因是编译器正在应用内联优化。您可以使用__attribute((noinline))
规范禁用此功能,但如果性能是您的目标,请让编译器内联它。
如果指定__restrict
关键字,则编译器将仅生成快速路径代码:https://goo.gl/g3jUfQ
然而,这并不意味着编译器会为你神奇地处理对齐,所以要注意你传递给函数的内容。