为了并行化我的基于数组的代码,我试图弄清楚如何利用英特尔 AVX 内在函数对大型数组执行并行操作。
从我读到的文档中,256 位 AVX vector 将支持最多 8 个并行 32 位整数/32 位 float 或最多 4 个并行 64 位 double 。浮点部分没有给我任何问题并且工作正常,但是整数 AVX 函数让我很头疼,让我使用以下代码来演示:
命令行选项 -mavx 与兼容 AVX 的 Intel 处理器一起使用。我不会使用 AVX2 功能。编译将在 Ubuntu 16.04 上使用 GNU99 C 完成。
AVX FP:
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
int main()
{
float data[8] = {1.f,2.f,3.f,4.f,5.f,6.f,7.f,8.f};
__m256 points = _mm256_loadu_ps(&data[0]);
for(int i = 0; i < 8; i++)
printf("%f\n",points[i]);
return 0;
}
输出:
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
这完全是应该的,但是在使用整数加载 AVX 函数时情况并非如此:
AVX INT:
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
int main()
{
int data[8] = {1,2,3,4,5,6,7,8};
__m256i points = _mm256_loadu_si256((__m256i *)&data[0]);
for(int i = 0; i < 8; i++)
printf("%d\n",points[i]);
return 0;
}
输出:
1
3
5
7
1048576 [ out of bounds ]
0 [ out of bounds ]
1 [ out of bounds ]
3 [ out of bounds ]
如您所见,加载仅在 __m256i 类型变量中生成 4 个元素,其中只有第一个、第三个、第五个和第七个元素从 原始数组。超出第四个元素的引用超出范围。
如何产生将整个数据集按顺序加载到整数 AVX 数据类型的预期结果,就像 AVX float 据类型一样?
最佳答案
您正在使用 GNU C 扩展来索引具有 []
的 vector 而不是将其存储回数组。英特尔的内部函数文档对此没有任何说明,并且并非所有编译器都支持它(例如 MSVC 不支持)。
GCC 定义 __m256i
作为 GNU C native vector of long long
. <immintrin.h>
没有定义不同的 __m256i
int
的 SIMD vector 的类型或 short
, 和 __m256i
不记得它来自哪里/它是如何设置的。 (与 ps
和 pd
有单独的 C 类型的 FP vector 不同,因此如果要在 __m128d _mm_castps_pd(__m128)
vector 上使用 shufpd
或 unpcklpd
,则必须使用 ps
)
您可以typedef
native vector 类型,如 v8si
自己(参见上一个 gcc 文档链接),或使用库 like Agner Fog's VCL为您提供 Vec8i
之类的类型(8 签名 int
) 或 Vec32uc
(32 个无符号 char
)。它们有运算符重载,可让您编写 a + b
而不是 _mm256_add_epi32(a, b)
或 _mm256_add_epi8(a,b)
取决于类型。或使用 []
而不是 _mm_extract_epi32
/epi8/epi16/epi64。
见 print a __m128i variable用于循环/打印英特尔内部 SIMD 变量的元素的可移植和安全/正确的方法。 TL:DR: _mm_store
/_mm256_store
到 tmp 数组并为其编制索引。它是可移植的,并且可以优化(对于整数到 pextrd
或对于 FP 只是一个随机播放),在简单的情况下没有实际的存储/重新加载。
关于c - 英特尔 AVX 在 C 中的 _mm256_load_si256 整数运算不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47492017/