gpt4 book ai didi

C++ AVX2 内在函数非标准大小

转载 作者:行者123 更新时间:2023-12-02 15:52:31 26 4
gpt4 key购买 nike

我正在尝试将 AVX2 内部函数与 C++ 一起使用。我正在使用 float (__m256)。现在一个寄存器可以容纳 8 个 float 。但是,如果我的 float 少于 8 个(假设我有 5 个),会发生什么情况。在这种情况下,较低的 3 个 float 具有垃圾值。

float a[5] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float b[5] = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f};

__m256 _a = _mm256_loadu_ps(a);
__m256 _b = _mm256_loadu_ps(b);

__m256 _c = _mm256_div_ps(_a, _b);

for(int i=0; i<8; ++i)
cout << _c[i] << endl;

我在下面的屏幕截图中得到的结果:

Result

有什么办法可以将结果中的最后3个数字变为0吗?我不想运行循环,因为这会违背使用 AVX 的目的。此外, float 的数量(本例中为 5)是可变的。

我是 AVX 新手,非常需要一些帮助。

在更大的问题中,我从数据流中读取数组,因此事先不知道数组的大小,以便能够在数组末尾附加 0 而无需运行循环。

最佳答案

float a[5] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float b[5] = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f};

__m256 _a = _mm256_loadu_ps(a);
__m256 _b = _mm256_loadu_ps(b);

这是未定义的行为,因为您正在读取数组之外的内容。

您可以使用_mm256_setzero_ps()清除_a_b中的所有元素:

__m256 _a = _mm256_setzero_ps;
__m256 _b = _mm256_setzero_ps;

将 5 个元素加载到 __m256 寄存器中有点棘手。如果可能的话,可以用 8 个元素来声明。我相信 C++ 将使用 0.0f 进行值初始化。

float a[8] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float b[8] = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f};

如果您无法声明包含 8 个元素的数组,那么我可能会使用 GCC 和 Clang 尝试类似的操作:

__m256 _a = _mm256_setzero_ps(), _b = _mm256_setzero_ps();
memcpy(&_a, a, 5*sizeof(float));
memcpy(&_b, b, 5*sizeof(float));
<小时/>

您还可以复制到中间数组并允许编译器优化:

float a[5] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float b[5] = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
float t[0] = {0.0f};

memcpy(t, a, 5*sizeof(float));
__m256 _a = _mm256_loadu_ps(t);
memcpy(t, b, 5*sizeof(float));
__m256 _b = _mm256_loadu_ps(t);

(编者注:这可能会编译为与 memcpy 大致相同的 asm 到 __m256 对象中。使用当前的编译器,它实际上会复制到堆栈并导致存储转发停止已重新加载。)

<小时/>

最后一种可能性是加载一个完整的 __m128,在第二个 __m128 中设置一个元素,然后将两个 __m128 组合成一个__m256。我对此没有太多经验,但这可能会满足您的要求。我没有测试过:

float a[5] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float b[5] = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f};

__m256 _a = _mm256_set_m128 (_mm_loadu_ps(a+0), _mm_load_ps1(a+4));
__m256 _b = _mm256_set_m128 (_mm_loadu_ps(b+0), _mm_load_ps1(b+4));

_mm_load_ps1 会将第一个元素(a[4]b[4])广播到其余元素中。其余元素将为 0,但它们也不会是随机垃圾。当您进行计算时,您将它们视为“不关心”。

如果您确实需要最后三个元素为 0.0f,那么这应该可以。但我相信这会花费您两条额外的指令,而不是 _mm_load_ps1

// x set to {5.0f, 0.0f, 0.0f, 0.0f}
__m128 x = _mm_insert_ps(_mm_setzero_ps(), _mm_load_ps1(a+4), 0);

a 的完整语句如下所示:

__m256 _a = _mm256_set_m128 (_mm_loadu_ps(a+0),
_mm_insert_ps(_mm_setzero_ps(), _mm_load_ps1(a+4), 0));

在退出处理 __m256 数据类型的例程之前,您可能需要调用 _mm256_zeroupper。查看类似 Using AVX CPU instructions: Poor performance without “/arch:AVX” 的问题和 Using xmm parameter in AVX intrinsics .

无论您做出什么决定,您都应该对应用程序的性能进行基准测试,以确定哪个最适合您的程序。

另请参阅Intel Intrinsics Guide .

关于C++ AVX2 内在函数非标准大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58902478/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com