我一直试图找出应用程序中的性能问题,并最终将其缩小到一个非常奇怪的问题.如果VZEROUPPER指令被注释掉,则下面的代码在Skylake CPU(i5-6500)上运行速度慢6倍.我测试了Sandy Bridge和Ivy Bridge CPU,两种版本都以相同的速度运行,有或没有VZEROUPPER.
现在我VZEROUPPER对这个代码有了一个相当好的想法,而且我认为当没有VEX编码指令并且没有调用可能包含它们的任何函数时,它对这个代码根本不重要.事实上它不支持其他支持AVX的CPU似乎支持这一点.英特尔®64和IA-32架构优化参考手册中的表11-2也是如此
那么发生了什么?
我留下的唯一理论是,CPU中存在一个错误,它错误地触发了"保存AVX寄存器的上半部分"程序,而不应该这样做.或者其他一些同样奇怪的东西.
这是main.cpp:
#include <immintrin.h>
int slow_function( double i_a, double i_b, double i_c );
int main()
{
/* DAZ and FTZ, does not change anything here. */
_mm_setcsr( _mm_getcsr() | 0x8040 );
/* This instruction fixes performance. */
__asm__ __volatile__ ( "vzeroupper" : : : );
int r = 0;
for( unsigned j = 0; j < 100000000; ++j )
{
r |= slow_function(
0.84445079384884236262,
-6.1000481519580951328, …Run Code Online (Sandbox Code Playgroud) 我希望对zmm 0-31寄存器组的四字字元素执行整数运算操作,并保留这些操作产生的进位.看起来这只有在数据在通用寄存器集中处理时才有可能.
因此,我想将信息从一个zmm 0-31寄存器复制到一个通用寄存器.在处理通用寄存器中的64位数据之后,我想将数据返回到它来自的相同QuadWord位置的原始zmm 0-31寄存器.我知道我可以使用命令将数据从通用寄存器rax移动到AVX512寄存器zmm26 QuadWord位置5
vpbroadcastq zmm26{k5}{z},rax
Run Code Online (Sandbox Code Playgroud)
其中8位掩码k5 =十进制32,允许将数据广播到zmm26的第5个QuadWord,z = 1表示zmm26中没有其他QWord受影响,rax是数据源自的位置.
但是我找不到一个反向命令,它将寄存器zmm26,四字5中的数据写入rax寄存器.看来我只能使用vmovq rax,xmm1命令将最不重要的QuadWord从AVX寄存器复制到通用寄存器.并且没有使用掩码zmm 0-31源的广播命令.
我很高兴知道我的命令选项是从zmm 0-31寄存器到rax寄存器获得特定的QuadWord.此外,除了英特尔手册之外,AVX512指令集还有其他任何描述性信息来源吗?
考虑x86中的以下循环:
; on entry, rdi has the number of iterations
.top:
; some magic happens here to calculate a result in rax
mov [array + rdi * 8], rax ; store result in output array
dec rdi
jnz .top
Run Code Online (Sandbox Code Playgroud)
它很简单:有些东西计算结果rax(未显示)然后我们将结果存储到数组中,与我们索引时的顺序相反rdi.
我想转换上面的循环而不是对内存进行任何写入(我们可以假设未显示的计算不会写入内存).
只要循环计数rdi有限,我就可以使用ymmregs 提供的充足空间(512字节)来保存值,但实际上这样做似乎很尴尬,因为你不能"索引"任意寄存器.
一种方法是始终将ymm一个元素的整个"数组" 寄存器混洗,然后将元素插入新释放的位置.
像这样的东西:
vpermq ymm3, ymm3, 10_01_00_11b ; left rotate ymm by qword
vpermq ymm2, ymm2, 10_01_00_11b ; left rotate ymm by qword
vpermq ymm1, ymm1, 10_01_00_11b …Run Code Online (Sandbox Code Playgroud) 假设你有值rax,rdx你想加载到xmm寄存器中.
一种方法是:
movq xmm0, rax
pinsrq xmm0, rdx, 1
Run Code Online (Sandbox Code Playgroud)
虽然这很慢!有没有更好的办法?