AVX unpackhipd/unpacklopd 整个 256 位寄存器的模拟
AVX unpackhipd/unpacklopd analogue for whole 256 bit register
假设我有两个 256 位寄存器,每个寄存器有四个双精度值,x
和 y
。 _mm256_unpacklo_pd(x, y)
(VUNPCKLPD
) 的输出是:[x0, y0, x2, y2]
(因为每个 128 位行都是单独处理的)。我要达到[x0, y0, x1, y1]
.
这个有intrinsic/instruction吗?或者,如果没有,达到预期结果的最快方法是什么?
请注意,您想要的所有值都在输入向量的低通道中。
每个输入的 128b 低半部分的 _mm_unpacklo_pd
/ _mm_unpackhi_pd
将为 vinsertf128
设置。 (如果针对 Sandybridge/Ivybridge 进行调整,您可以对 128b 操作使用整数洗牌 (vpunpcklqdq / hqdq
) 以获得比 FP 洗牌更好的吞吐量。因为我认为这不会对任何支持 AVX1 的 CPU 造成伤害,它是不错的主意。)
如果高低通道需要相同的东西,则使用 256b 通道内解包指令并洗牌该结果的 128b 通道。 _m256_permute2f128_pd
在可能的情况下使用 gcc/clang 编译为 vinsertf128
,但不使用 ICC 或 MSVC,因此编写
更有效
// much faster on Ryzen/KNL, same on Intel mainstream
__m256d lohalves_insert(__m256d lo, __m256d hi) {
return _mm256_insertf128_pd(lo, _mm256_castpd256_pd128(hi), 1);
}
在 the Godbolt compiler explorer 上查看各种编译器如何优化这些内容。
可能有一种只用 AVX1 就可以完成它的 2 指令方法,但可能不是。
使用 AVX2,您可以 vinsertf128
将每个输入的低 128b 放入单个向量的两个通道中。然后使用 AVX2 vpermpd
将通道中的元素洗牌到它们的最终位置。
这在 Ryzen 上比两个 128b vunpckl/hpd
+ vinsertf128
更差,但在 Intel 上的吞吐量更高。 2 次车道交叉洗牌 (3+3c = 6c) 与 1+1(资源冲突)+3c = 5c 对于 3-shuffle 方式的延迟更差,在 Intel Haswell 和更高版本上,或者在 Sandybridge/Ivybridge if您不对 128b 操作使用整数洗牌。 (参见 Agner Fog 的 insn 表,x86 标签 wiki 中的链接。)
在我的例子中,我实际上需要处理数据的 high/low 部分,所以两个向量需要四个指令:unpackhi/unpacklo 和洗牌它们的 low/high 一半
假设我有两个 256 位寄存器,每个寄存器有四个双精度值,x
和 y
。 _mm256_unpacklo_pd(x, y)
(VUNPCKLPD
) 的输出是:[x0, y0, x2, y2]
(因为每个 128 位行都是单独处理的)。我要达到[x0, y0, x1, y1]
.
这个有intrinsic/instruction吗?或者,如果没有,达到预期结果的最快方法是什么?
请注意,您想要的所有值都在输入向量的低通道中。
每个输入的 128b 低半部分的_mm_unpacklo_pd
/ _mm_unpackhi_pd
将为 vinsertf128
设置。 (如果针对 Sandybridge/Ivybridge 进行调整,您可以对 128b 操作使用整数洗牌 (vpunpcklqdq / hqdq
) 以获得比 FP 洗牌更好的吞吐量。因为我认为这不会对任何支持 AVX1 的 CPU 造成伤害,它是不错的主意。)
如果高低通道需要相同的东西,则使用 256b 通道内解包指令并洗牌该结果的 128b 通道。 _m256_permute2f128_pd
在可能的情况下使用 gcc/clang 编译为 vinsertf128
,但不使用 ICC 或 MSVC,因此编写
// much faster on Ryzen/KNL, same on Intel mainstream
__m256d lohalves_insert(__m256d lo, __m256d hi) {
return _mm256_insertf128_pd(lo, _mm256_castpd256_pd128(hi), 1);
}
在 the Godbolt compiler explorer 上查看各种编译器如何优化这些内容。
可能有一种只用 AVX1 就可以完成它的 2 指令方法,但可能不是。
使用 AVX2,您可以 vinsertf128
将每个输入的低 128b 放入单个向量的两个通道中。然后使用 AVX2 vpermpd
将通道中的元素洗牌到它们的最终位置。
这在 Ryzen 上比两个 128b vunpckl/hpd
+ vinsertf128
更差,但在 Intel 上的吞吐量更高。 2 次车道交叉洗牌 (3+3c = 6c) 与 1+1(资源冲突)+3c = 5c 对于 3-shuffle 方式的延迟更差,在 Intel Haswell 和更高版本上,或者在 Sandybridge/Ivybridge if您不对 128b 操作使用整数洗牌。 (参见 Agner Fog 的 insn 表,x86 标签 wiki 中的链接。)
在我的例子中,我实际上需要处理数据的 high/low 部分,所以两个向量需要四个指令:unpackhi/unpacklo 和洗牌它们的 low/high 一半