c – 如何改进编译器对SSE内在函数的处理?

c – 如何改进编译器对SSE内在函数的处理?,第1张

概述阅读 this interesting article on the results of intrinsic-guided optimization of SSE code in different C++ compilers后,我决定对自己进行测试,特别是因为该帖已有几年了.我使用的MSVC在帖子的作者(虽然在VS 2010版本中)执行的测试中表现非常糟糕,并且决定坚持一个非常基本的场景:将一 阅读 this interesting article on the results of intrinsic-guided optimization of SSE code in different C++ compilers后,我决定对自己进行测试,特别是因为该帖已有几年了.我使用的MSVC在帖子的作者(虽然在VS 2010版本中)执行的测试中表现非常糟糕,并且决定坚持一个非常基本的场景:将一些值打包到XMM寄存器中并进行简单的 *** 作,如加法.在文章中,_mm_set_ps翻译成一个奇怪的标量移动和解包指令序列,所以让我们看看:

int _tmain(int argc,_TCHAR* argv[]){    __m128 foo = _mm_set_ps(1.0f,2.0f,3.0f,4.0f);    __m128 bar = _mm_set_ps(5.0f,6.0f,7.0f,8.0f);    __m128 ret = _mm_add_ps(foo,bar);    // need to do something so vars won't be optimized out in Release    float *f = (float *)(&ret);    for (int i = 0; i < 4; i++)     {        cout << "f[" << i << "] = " << f[i] << endl;    }}

接下来,我在调试器中编译并运行它,查看反汇编:

调试:

__m128 foo = _mm_set_ps(1.0f,4.0f);
00B814F0 movaps xmm0,xmmword ptr ds:[0B87840h]
00B814F7 movaps xmmword ptr [ebp-190h],xmm0
00B814FE movaps xmm0,xmmword ptr [ebp-190h]
00B81505 movaps xmmword ptr [foo],xmm0
__m128 bar = _mm_set_ps(5.0f,8.0f);
00B81509 movaps xmm0,xmmword ptr ds:[0B87850h]
00B81510 movaps xmmword ptr [ebp-170h],xmm0
00B81517 movaps xmm0,xmmword ptr [ebp-170h]
00B8151E movaps xmmword ptr [bar],xmm0
__m128 ret = _mm_add_ps(foo,bar);
00B81522 movaps xmm0,xmmword ptr [bar]
00B81526 movaps xmm1,xmmword ptr [foo]
00B8152A addps xmm1,xmm0
00B8152D movaps xmmword ptr [ebp-150h],xmm1
00B81534 movaps xmm0,xmmword ptr [ebp-150h]
00B8153B movaps xmmword ptr [ret],xmm0

完全糊涂;为什么将xmmword放入__m128需要四个MOVAPS?首先,它将数据放入xmm0(我假设它是存储在某处的四个浮点值的文字,不知道如何查看它),然后复制xmm0指向ebp和偏移量的某处,只是将其从那里是xmm0(?),最后到了应该存储它的变量的位置.为什么这么多工作?

发布:
这次我期望编译器完全避免将xmmword存储在内存中,只需将其中一个放入xmm0,将其他放入xmm1,执行ADDPS,将结果放入内存并完成.相反,我得到了:

__m128 foo = _mm_set_ps(1.0f,4.0f);
__m128 bar = _mm_set_ps(5.0f,8.0f);
__m128 ret = _mm_add_ps(foo,bar);
003E1009 movaps xmm0,xmmword ptr ds:[3E2130h]
003E1010 push esi
003E1011 movaps xmmword ptr [esp+10h],xmm0

显然,不需要ADDPS.我猜测编译器注意到两个xmmwords是编译时常量所以它只是添加它们,将结果作为文字放在代码中?奇怪的推动可能与后面的for循环有关,因为就我所知,esi被用作循环计数器.仍然,为什么不将数据段中的预先计算的文字放入xmm0然后放入局部变量(特别是10h),为什么不直接使用文字?

总而言之,DeBUG版本比我预期的更愚蠢(或者我可能没有得到什么),而Release版本出乎意料地聪明.任何解释此行为的评论将不胜感激.谢谢.

编辑:答案是非常有启发性的,但我仍然想知道我是否可以做任何事情来改善编译器输出,这就是为什么我要求将此问题解释为当前形式的问题.

例如,是否有可能以某种方式引导编译器不将foo和bar存储在内存中(因为我在添加后不需要它们),只需将它们加载到xmmN寄存器并保存在那里?可能也会退回?引用文章的作者说,MSVC只是“完全按照它所说的去做”.有没有明确写出__asm块的任何方法可以更好(读取:避免内存传输)代码?谢谢.

解决方法 这只是代码生成器工作方式的正常副作用. _mm_set_ps()有两个不同的工作要做.它首先必须从4个参数中建立__m128值.你选择了简单的方法,它变得更加复杂:

float x = 1.0f;__m128 foo = _mm_set_ps(x,4.0f);

具有完全不同的codegen:

00C513DD  movss       xmm0,DWord ptr ds:[0C5585Ch]  00C513E5  movss       xmm1,DWord ptr [x]  00C513EA  movaps      xmm2,xmmword ptr ds:[0C55860h]  00C513F1  unpcklps    xmm0,xmm1  00C513F4  unpcklps    xmm2,xmm0  00C513F7  movaps      xmmword ptr [ebp-100h],xmm2

然后第二个工作是将它移动到__m128变量中,这很容易

00C513FE  movaps      xmm0,xmmword ptr [ebp-100h]  00C51405  movaps      xmmword ptr [foo],xmm0

这还没有优化,只是因为在DeBUG版本中关闭了优化器.代码生成器不会进行任何优化尝试,这不是它的工作.

当然,优化器能够在编译时计算结果.这甚至适用于复杂的例子,你已经看到了这个:

00EE1284  movaps      xmm0,xmmword ptr ds:[0EE3260h]
总结

以上是内存溢出为你收集整理的c – 如何改进编译器对SSE内在函数的处理?全部内容,希望文章能够帮你解决c – 如何改进编译器对SSE内在函数的处理?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1214787.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存