gpt4 book ai didi

c# - 如何在两个 AVX2 vector 之间交换 128 位部分

转载 作者:行者123 更新时间:2023-12-01 14:03:55 25 4
gpt4 key购买 nike

问题:我有 4 个 256 位 AVX2 vector (A、B、C、D),我需要执行它们各自的 128 位部分以及两个不同 vector 之间的交换操作。这是我需要做的转换。

             Original                      Transformed
|| Low Lane || High Lane|| || Low Lane || High Lane||
A = || L1 || H1 || = > || L1 || L2 ||
B = || L2 || H2 || = > || H1 || H2 ||
C = || L3 || H3 || = > || L3 || L4 ||
D = || L4 || H4 || = > || H3 || H4 ||

Visualization

基本上我需要按以下顺序将输出 L1、L2、L3、L4、H1、H2、H3、H4 存储到数组中。

我目前的解决方案是使用:
4x _mm256_blend_epi32(最坏情况:延迟 1,吞吐量 0.35)
4x _mm256_permute2x128_si256(最坏情况:延迟 3,吞吐量 1)
// (a, c) = block0, (b, d) = block1
a = Avx2.Permute2x128(a, a, 1);
var template = Avx2.Blend(a, b, 0b1111_0000); // H1 H2
a = Avx2.Blend(a, b, 0b0000_1111); // L2 l1
a = Avx2.Permute2x128(a, a, 1); // L1 l2
b = template;

c = Avx2.Permute2x128(c, c, 1);
template = Avx2.Blend(c, d, 0b1111_0000); // H3 H4
c = Avx2.Blend(c, d, 0b0000_1111); // L4 L3
c = Avx2.Permute2x128(c, c, 1); // L3 l4
d = template;

// Store keystream into buffer (in corrected order = [block0, block1])
Avx2.Store(outputPtr, a);
Avx2.Store(outputPtr + Vector256<uint>.Count, c);
Avx2.Store(outputPtr + Vector256<uint>.Count * 2, b);
Avx2.Store(outputPtr + Vector256<uint>.Count * 3, d);

注:如果您想知道,我正在使用 C#/NetCore 来做 AVX2!随意使用 C/C++ 中的示例。

有没有更好或更有效的方法来做到这一点?

编辑

接受答案为 C#
var tmp = Avx2.Permute2x128(a, b, 0x20);
b = Avx2.Permute2x128(a, b, 0x31);
a = tmp;
tmp = Avx2.Permute2x128(c, d, 0x20);
d = Avx2.Permute2x128(c, d, 0x31);
c = tmp;

最佳答案

如果我理解正确,我认为您可以在没有此 2x4 转置的混合指令的情况下离开,创建选择所需车道的新变量。就像是:

__m256i a;    // L1 H1
__m256i b; // L2 H2
__m256i c; // L3 H3
__m256i d; // L4 H4

__m256i A = _mm256_permute2x128_si256(a, b, 0x20); // L1 L2
__m256i B = _mm256_permute2x128_si256(a, b, 0x31); // H1 H2
__m256i C = _mm256_permute2x128_si256(c, d, 0x20); // L3 L4
__m256i D = _mm256_permute2x128_si256(c, d, 0x31); // H3 H4

您仍然有 vperm2i128 的 3 个周期延迟指令,但是当您有数据跨越 128 位 channel 时,您总是会拥有该指令。这 4 个 shuffle 是独立的,因此它们可以流水线化(ILP); Intel 和 Zen 2 的吞吐量为 1/clock vperm2i128 ( https://agner.org/optimize/https://uops.info/ )。

如果幸运的话,编译器会将 L1,L2 和 L3,L4 shuffle 优化为 vinserti128 AMD Zen 1 的运行效率更高(1 uop 而不是 8;跨车道洗牌被分成多个 128 位 uop。)

这 4 次 shuffle 需要 4 uop 用于 shuffle 端口(Intel 上的端口 5); Intel 和 Zen2 对于这些 shuffle 仅有 1/clock shuffle 吞吐量。如果这将成为您循环中的瓶颈,请考虑@chtz 的答案,该答案通过进行 2 次洗牌来排列需要移动以准备廉价混合的 4 条 channel ( vpblendd),从而消耗更多的前端吞吐量。相关: What considerations go into predicting latency for operations on modern superscalar processors and how can I calculate them by hand?

关于c# - 如何在两个 AVX2 vector 之间交换 128 位部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61866755/

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