在为AVX256,AVX512和一天AVX1024设计前瞻性算法时,考虑到大SIMD宽度的完全通用置换的潜在实现复杂性/成本,我想知道即使在AVX512中通常保持隔离128位操作是否更好?
特别是考虑到AVX有128位单元来执行256位操作.
为此,我想知道在所有512位向量中AVX512置换类型操作之间是否存在性能差异,而在 512位向量的每个4x128位子向量中是否存在置换类型操作?
我有一大块内存,比如256 KiB或更长.我想计算整个块中的1位数,或者换句话说:为所有字节添加"种群计数"值.
我知道AVX-512有一个VPOPCNTDQ指令,它计算512位向量中每个连续64位的1位数,而IIANM应该可以在每个周期发出其中一个(如果一个适当的SIMD向量寄存器是可用) - 但我没有任何编写SIMD代码的经验(我更像是一个GPU人).此外,我不是100%确定AVX-512目标的编译器支持.
在大多数CPU上,仍然没有(完全)支持AVX-512; 但AVX-2广泛可用.我无法找到类似于VPOPCNTDQ的低于512位的向量化指令,所以即使理论上我也不确定如何使用支持AVX-2的CPU快速计算位数; 也许这样的事情存在,我只是错过了它?
无论如何,对于两个指令集中的每一个,我都很欣赏一个简短的C/C++函数 - 使用一些内部包装库或内联汇编.签名是
uint64_t count_bits(void* ptr, size_t size);
Run Code Online (Sandbox Code Playgroud)
笔记:
通常有两种类型的SIMD指令:
A.使用对齐的内存地址的那些,如果地址未在操作数大小边界上对齐,则会引发一般保护(#GP)异常:
movaps xmm0, xmmword ptr [rax]
vmovaps ymm0, ymmword ptr [rax]
vmovaps zmm0, zmmword ptr [rax]
Run Code Online (Sandbox Code Playgroud)
B.以及使用未对齐内存地址的那些,不会引发此类异常:
movups xmm0, xmmword ptr [rax]
vmovups ymm0, ymmword ptr [rax]
vmovups zmm0, zmmword ptr [rax]
Run Code Online (Sandbox Code Playgroud)
但是我只是好奇,为什么我要用脚射击自己并使用第一组的对齐记忆指令呢?
我在AVX2指令集中看到,英特尔用不同的指令来区分整数,双精度和浮点的XOR操作。对于整数,为“ VPXORD”,对于双精度为“ VXORPD”,为浮点数“ VXORPS”
但是,根据我的理解,它们都应该对二进制数据进行相同的XOR操作。例如,两个256位寄存器的XOR,与实际数据类型无关。为什么我们需要对不同的数据类型使用不同的指令?
说,我想清除4个zmm寄存器.
以下代码是否会提供最快的速度?
vpxorq zmm0, zmm0, zmm0
vpxorq zmm1, zmm1, zmm1
vpxorq zmm2, zmm2, zmm2
vpxorq zmm3, zmm3, zmm3
Run Code Online (Sandbox Code Playgroud)
在AVX2上,如果我想清除ymm寄存器,vpxor比vxorps更快,速度更快,因为vpxor可以在多个单元上运行.
在AVX512上,我们没有用于zmm寄存器的vpxor,只有vpxorq和vpxord.这是清除寄存器的有效方法吗?当我使用vpxorq清除zmm寄存器时,CPU是否足够智能,不会对zmm寄存器的先前值产生错误依赖?
在没有物理AVX512 CPU测试的情况下 - 也许有人在Knights Landing上测试过?是否有任何延迟发布?
我对于在分支方面理论上掩蔽可以做什么感到困惑.假设我有一个Skylake-SP(哈,我希望......),我们忽略了编译器功能,理论上可能的是:
如果分支条件依赖于静态标志,并且所有分支都将数组设置为计算结果,假设编译器不将其优化为两个单独的循环,它是否可以向量化?
do i = 1, nx
if (my_flag .eq. 0) then
a(i) = b(i) ** 2
else
a(i) = b(i) ** 3
end if
end do
Run Code Online (Sandbox Code Playgroud)
如果仅作为分支的子集设置有问题的值,它可以矢量化吗?
do i = 1, nx
if (my_flag .eq. 0) then
a(i) = b(i) ** 2
end if
end do
Run Code Online (Sandbox Code Playgroud)
如果分支条件本身依赖于矢量数据,它可以矢量化吗?
do i = 1, nx
if (c(i) > 0) then
a(i) = b(i) ** 2
else
a(i) = b(i) ** 3
end if
end do
Run Code Online (Sandbox Code Playgroud) 当我做一个写掩码的AVX-512商店时,如下所示:
vmovdqu8 [rsi] {k1}, zmm0
Run Code Online (Sandbox Code Playgroud)
如果[rsi, rsi + 63]
未映射的存储器的某些部分未被映射但是所有那些位置的写掩码为零(即,由于掩码实际上未修改数据),指令是否会发生故障.
另一种询问方式是这些AVX-512屏蔽存储是否具有类似的故障抑制能力,以便vmaskmov
在AVX中引入.
假设你打电话 _mm512_mask_store_ps,从 CPU 的写入缓冲区的角度来看,它是作为大小为 64 字节的存储执行(带有某种掩码)还是在内部作为大小为 4 字节的多个存储执行?
为了防止store-to-load转发停顿,必须将存储的粒度(大小)与后续加载到同一内存位置的粒度相匹配。希望这个问题是有道理的,我不是 CPU 架构专家。
请考虑以下最小示例minimal.cpp
(https://godbolt.org/z/x7dYes91M)。
#include <immintrin.h>
#include <algorithm>
#include <ctime>
#include <iostream>
#include <numeric>
#include <vector>
#define NUMBER_OF_TUPLES 134'217'728UL
void transform(std::vector<int64_t>* input, std::vector<double>* output, size_t batch_size) {
for (size_t startOfBatch = 0; startOfBatch < NUMBER_OF_TUPLES; startOfBatch += batch_size) {
size_t endOfBatch = std::min(startOfBatch + batch_size, NUMBER_OF_TUPLES);
for (size_t idx = startOfBatch; idx < endOfBatch;) {
if (endOfBatch - idx >= 8) {
auto _loaded = _mm512_loadu_epi64(&(*input)[idx]);
auto _converted = _mm512_cvtepu64_pd(_loaded);
_mm512_storeu_epi64(&(*output)[idx], _converted);
idx += 8;
} else {
(*output)[idx] …
Run Code Online (Sandbox Code Playgroud)