AVX2的功能急剧下降

问题描述

我认识到Clang(10.0)和MSVC(16.7)生成的汇编程序具有非常不同的性能(对于Clang是〜3.3ns,对于MSVC是〜8ns)是通过同一块C ++代码和一些AVX2内在函数


代码正在计算可以从给定整数(10中分解出的rcx的最大指数,并且在分解出10的最大幂后也计算商

为弄清代码的作用,它计算(以10为底)给定整数的尾随零,并计算通过除去这些尾随零而获得的数字。例如,当输入为63700时,输出{637,2},当输入为1230000时,输出{123,4}

以下是可以重现代码的{godbolt}链接https://godbolt.org/z/5xoK3G

在231行中,您可以选择一个使用lambda(生成vmovups,重新加载2个标量存储并复制)和不使用lambda(不生成那些{{1} }。


要弄清楚原因,我做了几次测试。事实证明,差异来自以下事实:MSVC版本使用两个vmovups一个用于加载,一个用于存储)写回结果,而Clang使用两个vmovups(两个都对于商店)。

为证实这一假设,我做了几件事来强制MSVC生成mov而不是mov,并且所生成代码与Clang生成代码几乎相同。

问题是,为什么在这种情况下使用vmovups(或其他类似的矢量移动指令)会大大降低性能

我附加了两个由MSVC生成的程序集输出一个带有vmovups(因此执行〜{vmovups),另一个不带有8ns(因此执行〜vmovups):>

使用3.3ns :(此版本还包含/减少了堆栈指针;是否有必要?)

vmovups

没有00007FF7227114B0 sub rsp,18h 00007FF7227114B4 mov r8,rcx 00007FF7227114B7 lea rcx,[divtest_table_holder<unsigned int,5,9>::table (07FF7227133B0h)] 00007FF7227114BE vmovd xmm0,r8d 00007FF7227114C3 vpbroadcastd ymm0,xmm0 00007FF7227114C8 vpmulld ymm1,ymm0,ymmword ptr [divtest_table_holder<unsigned int,9>::table+4h (07FF7227133B4h)] 00007FF7227114D1 vpminud ymm0,ymm1,9>::table+28h (07FF7227133D8h)] 00007FF7227114DA vpcmpeqd ymm1,ymm1 00007FF7227114DE vpmovmskb eax,ymm1 00007FF7227114E2 popcnt edx,eax 00007FF7227114E6 tzcnt eax,r8d 00007FF7227114EB shr edx,2 00007FF7227114EE cmp eax,edx 00007FF7227114F0 cmovl edx,eax 00007FF7227114F3 movsxd rax,edx 00007FF7227114F6 mov dword ptr [rsp+8],edx 00007FF7227114FA mov ecx,dword ptr [rcx+rax*4] 00007FF7227114FD imul rcx,r8 00007FF722711501 mov eax,edx 00007FF722711503 shrx rcx,rcx,rax 00007FF722711508 mov qword ptr [rsp],rcx 00007FF72271150C vmovups xmm0,xmmword ptr [rsp] 00007FF722711511 vmovups xmmword ptr [rsp],xmm0 00007FF722711516 vzeroupper 00007FF722711519 add rsp,18h 00007FF72271151D ret

vmovups

此外,因为这是我编写的第一个SIMD代码,所以如果我做错了任何事情,我将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)