英特尔AVX在C中不一致_mm256_load_si256整数运算

时间:2017-11-26 00:53:50

标签: c x86 simd intrinsics avx

为了并行化我的基于数组的代码,我试图弄清楚如何利用英特尔AVX内在函数在大型数组上执行并行操作。

从我已经阅读的文档中可以看出,256位AVX向量最多可支持8个并行32位整数/ 32位浮点数或最多4个并行64位双精度数。浮动部分没有给我任何问题,工作正常,但整数AVX函数让我头疼,让我用下面的代码来演示:

命令行选项 -mavx 与符合AVX标准的Intel处理器配合使用。我不会使用AVX2功能。编译将在Ubuntu 16.04上使用GNU99 C完成。

AVX FP:

#myModal

输出:

{
  "type": "node",
  "request": "launch",
  "name": "Launch Node App",
  "program": "${workspaceFolder}/my-app/my-npm-start-script-dir/index.js"
}

这完全是应该的,但是当使用整数加载AVX函数时不是这种情况:

AVX INT:

#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

正如您所看到的,加载仅在__m256i类型变量中生成4个元素,其中只有第一个,第三个,第五个和第七个元素从 原始数组。超出第四个元素,引用超出范围。

如何将整个数据集按顺序加载到整数AVX数据类型中,与AVX浮点数据类型非常相似?

1 个答案:

答案 0 :(得分:7)

您正在使用GNU C扩展来使用[]索引向量,而不是将其存储回数组。针对内在函数的英特尔文档没有什么可说的,并非所有编译器都支持它(例如MSVC不支持)。

GCC将__m256i定义为GNU C native vector of long long<immintrin.h>没有为__m256iint的SIMD向量定义不同的short类型,而__m256i并未记住有关其位置的任何内容来自/如何设置。 (与对于pspd有单独C类型的FP向量不同,如果要使用__m128d _mm_castps_pd(__m128)shufpd,则必须unpcklpd ps向量)

您可以typedef自己使用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。

有关便携式和安全/正确的方法来循环/打印出英特尔固有SIMD变量的元素,请参阅print a __m128i variable。 TL:DR:_mm_store / _mm256_store到tmp数组并索引。它是可移植的,并且它会优化(对于整数的pextrd或者对FP来说只是一个shuffle),在简单的情况下没有实际的存储/重新加载。