gpt4 book ai didi

c - 优化 C 代码中的汇编代码冗余

转载 作者:太空狗 更新时间:2023-10-29 17:12:24 26 4
gpt4 key购买 nike

我正在尝试通过研究使用 -O3 优化在 gcc 中编译的简单 C 代码来学习矢量化。更具体地说,编译器矢量化的程度如何。这是一个能够通过更复杂的计算来验证 gcc -O3 性能的个人旅程。我知道传统观点认为编译器比人更好,但我从不认为这种观点是理所当然的。

不过,在我的第一个简单测试中,我发现 gcc 做出的一些选择非常奇怪,而且老实说,在优化方面存在严重疏忽。我愿意假设编译器有些东西是有目的的并且知道一些我不知道的 CPU(在这种情况下是 Intel i5-2557M)。但我需要一些知识渊博的人的确认。

我的简单测试代码(段)是:

int i;
float a[100];

for (i=0;i<100;i++) a[i]= (float) i*i;

得到的for循环对应的汇编代码(段)如下:

.L6:                        ; loop starts here
movdqa xmm0, xmm1 ; copy packed integers in xmm1 to xmm0
.L3:
movdqa xmm1, xmm0 ; wait, what!? WHY!? this is redundant.
cvtdq2ps xmm0, xmm0 ; convert integers to float
add rax, 16 ; increment memory pointer for next iteration
mulps xmm0, xmm0 ; pack square all integers in xmm0
paddd xmm1, xmm2 ; pack increment all integers by 4
movaps XMMWORD PTR [rax-16], xmm0 ; store result
cmp rax, rdx ; test loop termination
jne .L6

我理解所有的步骤,并且在计算上,所有这些都是有道理的。不过,我不明白的是,gcc 选择在迭代循环中加入一个步骤,即在 之后立即用 xmm0 加载 xmm1>xmm0 加载了 xmm1。即

 .L6
movdqa xmm0, xmm1 ; loop starts here
.L3
movdqa xmm1, xmm0 ; grrr!

仅这一点就让我质疑优化器的健全性。显然,额外的 MOVDQA 不会干扰数据,但从表面上看,这似乎是 gcc 的严重疏忽。

在汇编代码的前面(未显示),xmm0xmm2 被初始化为一些对矢量化有意义的值,因此很明显,在循环开始时,代码必须跳过第一个 MOVDQA。但是为什么 gcc 不简单地重新排列,如下所示。

.L3
movdqa xmm1, xmm0 ; initialize xmm1 PRIOR to loop
.L6
movdqa xmm0, xmm1 ; loop starts here

或者甚至更好,只需初始化 xmm1 而不是 xmm0 并一起转储 MOVDQA xmm1xmm0 步骤!

我准备相信 CPU 足够聪明,可以跳过冗余步骤或类似的东西,但我怎么能相信 gcc 可以完全优化复杂的代码,如果它甚至可以变得如此简单代码对吗?或者有人可以提供一个合理的解释,让我相信 gcc -O3 是个好东西吗?

最佳答案

我不是 100% 确定,但看起来你的循环通过将它转换为 float 来破坏 xmm0,所以你在 中有整数值xmm1 然后复制到另一个寄存器(在本例中为 xmm0)。

虽然众所周知编译器有时会发出不必要的指令,但我真的看不出在这种情况下是怎么回事。

如果您希望 xmm0(或 xmm1)保持整数,则不要将 float 转换为第一个值。也许您想做的是:

 for (i=0;i<100;i++) 
a[i]= (float)(i*i);

但另一方面,gcc 4.9.2 似乎没有这样做:

g++ -S -O3 floop.cpp

.L2:
cvtdq2ps %xmm1, %xmm0
mulps %xmm0, %xmm0
addq $16, %rax
paddd %xmm2, %xmm1
movaps %xmm0, -16(%rax)
cmpq %rbp, %rax
jne .L2

clang 也没有(大约 3 周前的 3.7.0)

 clang++ -S -O3 floop.cpp


movdqa .LCPI0_0(%rip), %xmm0 # xmm0 = [0,1,2,3]
xorl %eax, %eax
.align 16, 0x90
.LBB0_1: # %vector.body
# =>This Inner Loop Header: Depth=1
movd %eax, %xmm1
pshufd $0, %xmm1, %xmm1 # xmm1 = xmm1[0,0,0,0]
paddd %xmm0, %xmm1
cvtdq2ps %xmm1, %xmm1
mulps %xmm1, %xmm1
movaps %xmm1, (%rsp,%rax,4)
addq $4, %rax
cmpq $100, %rax
jne .LBB0_1

我编译的代码:

extern int printf(const char *, ...);

int main()
{
int i;
float a[100];

for (i=0;i<100;i++)
a[i]= (float) i*i;

for (i=0; i < 100; i++)
printf("%f\n", a[i]);
}

(我添加了 printf 以避免编译器删除所有代码)

关于c - 优化 C 代码中的汇编代码冗余,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28706850/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com