Jon*_*anE 35 c c++ assembly gcc x86-64
我一直在玩x86-64程序集试图了解更多有关可用的各种SIMD扩展(MMX,SSE,AVX).
为了了解GCC如何将不同的C或C++构造转换为机器代码,我一直在使用Compiler Explorer,这是一个极好的工具.
在我的一个"游戏会话"期间,我想看看GCC如何优化整数数组的简单运行时初始化.在这种情况下,我试图将数字0到2047写入2048个无符号整数的数组.
代码如下:
unsigned int buffer[2048];
void setup()
{
  for (unsigned int i = 0; i < 2048; ++i)
  {
    buffer[i] = i;
  }
}
如果我启用优化和AVX-512指令,-O3 -mavx512f -mtune=intelGCC 6.3会生成一些非常聪明的代码:)
setup():
        mov     eax, OFFSET FLAT:buffer
        mov     edx, OFFSET FLAT:buffer+8192
        vmovdqa64       zmm0, ZMMWORD PTR .LC0[rip]
        vmovdqa64       zmm1, ZMMWORD PTR .LC1[rip]
.L2:
        vmovdqa64       ZMMWORD PTR [rax], zmm0
        add     rax, 64
        cmp     rdx, rax
        vpaddd  zmm0, zmm0, zmm1
        jne     .L2
        ret
buffer:
        .zero   8192
.LC0:
        .long   0
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   6
        .long   7
        .long   8
        .long   9
        .long   10
        .long   11
        .long   12
        .long   13
        .long   14
        .long   15
.LC1:
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
        .long   16
但是,当我测试通过添加标志使用GCC C编译器编译相同代码时将生成的内容-x c我真的很惊讶.
我希望类似的,如果不相同,结果却在C编译器似乎产生太多复杂想必也慢得多的机器代码.将所得的组件太大,贴在这里全面,但它可以在godbolt.org按照观看此链接.
生成的代码的片段,第58到83行,如下所示:
.L2:
        vpbroadcastd    zmm0, r8d
        lea     rsi, buffer[0+rcx*4]
        vmovdqa64       zmm1, ZMMWORD PTR .LC1[rip]
        vpaddd  zmm0, zmm0, ZMMWORD PTR .LC0[rip]
        xor     ecx, ecx
.L4:
        add     ecx, 1
        add     rsi, 64
        vmovdqa64       ZMMWORD PTR [rsi-64], zmm0
        cmp     ecx, edi
        vpaddd  zmm0, zmm0, zmm1
        jb      .L4
        sub     edx, r10d
        cmp     r9d, r10d
        lea     eax, [r8+r10]
        je      .L1
        mov     ecx, eax
        cmp     edx, 1
        mov     DWORD PTR buffer[0+rcx*4], eax
        lea     ecx, [rax+1]
        je      .L1
        mov     esi, ecx
        cmp     edx, 2
        mov     DWORD PTR buffer[0+rsi*4], ecx
        lea     ecx, [rax+2]
正如您所看到的,此代码具有许多复杂的移动和跳转,并且通常感觉像执行简单数组初始化的非常复杂的方式.
为什么生成的代码有这么大的差异?
与C编译器相比,GCC C++ - 编译器在优化C和C++中有效的代码方面是否更好?
Jes*_*ter 39
额外的代码用于处理未对齐,因为使用的指令vmovdqa64需要64字节对齐.
我的测试显示,即使标准没有,gcc确实允许另一个模块中的定义在C模式下覆盖此处的定义.该定义可能只符合基本对齐要求(4个字节),因此编译器不能依赖更大的对齐.从技术上讲,gcc .comm为此暂定定义发出汇编指令,而外部定义在该.data部分中使用正常符号.在链接期间,此符号优先于该符号.comm.
请注意,如果您更改要使用的程序,extern unsigned int buffer[2048];那么即使C++版本也会添加代码.相反,制作它static unsigned int buffer[2048];会将C版本变为优化版本.
| 归档时间: | 
 | 
| 查看次数: | 1797 次 | 
| 最近记录: |