GCC生成不需要的汇编代码

时间:2015-10-08 19:26:29

标签: c++ gcc assembly

我正在进行矢量化循环,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;是问题,而不是内联呼叫)

1 个答案:

答案 0 :(得分:1)

你得到“怪异的”代码,因为GCC不能对指针的对齐做出假设,所以你可以看到它首先执行对齐测试来确定它是否可以采用快速路径和一次做128位,或慢速做一次16位。

此外,您发现重复代码的原因是编译器正在应用内联优化。您可以使用__attribute((noinline))规范禁用此功能,但如果性能是您的目标,请让编译器内联它。

如果指定__restrict关键字,则编译器将仅生成快速路径代码:https://goo.gl/g3jUfQ

然而,这并不意味着编译器会为你神奇地处理对齐,所以要注意你传递给函数的内容。