如何从 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() 不对应任何底层处理器能力,它只是重新排序参数。
我有一组浮点数,我想以相反的顺序访问它们。在我的非矢量化代码中,这很容易。
这是我所拥有的数据的简化版本。
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() 不对应任何底层处理器能力,它只是重新排序参数。