如何从 float* 加载到 __m256 但在内存中向后读取而不是向前读取?

How to load into __m256 from a float* but reading backwards in memory as opposed to forwards?

我有一组浮点数,我想以相反的顺序访问它们。在我的非矢量化代码中,这很容易。

这是我所拥有的数据的简化版本。

float A[8] = {a, b, c, d, e, f, g, h};
float B[8] = {s, t, u, v, w, x, y, z};

这是我想做的操作。

float C[8] = {a*z, b*y, c*x, d*w, e*v, f*u, g*t, h*s};

我希望能够执行某种 load_ps 操作,它会给我这样的结果:

__m256 A_Loaded         = _mm256_load_ps(&A[0]);
                        = {a, b, c, d, e, f, g, h};

__m256 B_LoadedReversed = _mm256_loadr_ps(&B[7]);
                        = {z, y, x, w, v, u, t, s};

__m256 Output = _mm256_mul_ps(A_Loaded, B_LoadedReversed);
              = {a*z, b*y, c*x, d*w, e*v, f*u, g*t, h*s};

我拥有的其中一个数据源是查找 table,所以如果到了紧要关头,可以将其撤消,但我更愿意避免这种情况,因为这会使程序的其他区域复杂化。

我目前有一个使用 _mm256_set_ps() 并手动指向我需要的数据的拙劣解决方法,但这并不像我想要的那样有效。

我知道有'reversed' _mm256_set_ps() (_mm256_setr_ps()),但是好像没有我需要的_mm256_loadr_ps()

任何关于这个问题的想法和想法将不胜感激!提前致谢。

您不能将其表示为负载——所有负载都是“正向”的。

您将不得不使用洗牌操作。名称中包含“permute”或“shuf”的东西。如果 AVX2 可用,可能 _mm256_permutevar8x32_ps 对您来说是个不错的选择。它在一个洗牌指令中完成了所有工作,尽管它确实需要加载一个洗牌控制向量。如果只有 AVX1 可用,Dietrich 的回答提出了一种使用两个 AVX1 随机播放的方法。

像这样(如果我没有反转索引):

// AVX2
__m256 B_LoadedReversed = _mm256_permutevar8x32_ps(
                              _mm256_load_ps(&B[0]),  // load B[0..7]
                              _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7));

此类函数的参数之一是索引向量,或者对于其他洗牌,如通道内_mm256_permute_ps,它是一个 8 位立即值 (imm8)。

参数的每个元素都是源向量元素在目标向量中的位置。对于 imm8,有 2 位位置。

一些洗牌函数对给定向量的子向量执行多次洗牌,但不是这个。

许多 AVX+ 随机播放不会跨 通道(128 位组)随机播放,但这个会。

您可以使用 _mm256_permute_ps_mm_256_permute2f128_ps 分两步反转 __m256 中的顺序。

  • _mm256_permute_ps 允许您在每个“通道”内置换高和低 128 位块。

  • _mm_256_permute2f128_ps 允许您跨通道置换 128 位块。

是这样的:

__m256 b = _mm256_loadr_ps(&B[0]);
b = _mm256_permute_ps(b, _MM_SHUFFLE(3, 2, 1, 0));
b = _mm256_permute2f128_ps(b, b, 1);

英特尔内在函数指南中记录了这些说明:https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html

setr_ps 是如何工作的?

setr_ps() 如何反转事物?它只是颠倒了论点。这是我从 GCC 安装中提取的版本:

extern __inline __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm256_setr_ps (float __A, float __B, float __C, float __D,
                float __E, float __F, float __G, float __H)
{
  return _mm256_set_ps (__H, __G, __F, __E, __D, __C, __B, __A);
}

你可以看到,setr_ps() 不对应任何底层处理器能力,它只是重新排序参数。