You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效拆分单精度复数实部虚部到不同ymm寄存器?

优化复数序列拆分的AVX2实现

需求:将按[实部1, 虚部1, 实部2, 虚部2, …]格式存储的单精度复数序列加载到YMM寄存器,最终让ymm0存储所有实部、ymm1存储所有虚部。原实现使用4个跨通道洗牌操作,这类操作在部分设备上开销较高,希望找到更高效的实现方式。

原实现代码

// 此处负数代表虚部
float _f[] = {1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8};

int i[] = {0, 2, 4, 6, 1, 3, 5, 7};

__m256 a = _mm256_loadu_ps(_f);
__m256 b = _mm256_loadu_ps(_f+8);

__m256i x = _mm256_loadu_si256((void*)i);

__m256 c = _mm256_permutevar8x32_ps(a, x);
__m256 d = _mm256_permutevar8x32_ps(b, x);

__m256 e = _mm256_permute2f128_ps(c, d, 0x20);
__m256 f = _mm256_permute2f128_ps(c, d, 0x31);

高效优化方案

可以利用AVX2的_mm256_shuffle_ps(128位内固定模式洗牌,延迟和吞吐量更优)替代原方案中开销较高的_mm256_permutevar8x32_ps,仅保留必要的跨128位块合并操作,将高开销跨通道操作从4个减少到2个。

优化后代码

float _f[] = {1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8};

// 加载两组复数(每组4对)到YMM寄存器
__m256 a = _mm256_loadu_ps(_f);
__m256 b = _mm256_loadu_ps(_f + 8);

// 从每个寄存器内提取实部:每个128位块中选择索引0、2的元素
__m256 a_real = _mm256_shuffle_ps(a, a, 0x55); // 0x55对应二进制01010101
__m256 b_real = _mm256_shuffle_ps(b, b, 0x55);

// 从每个寄存器内提取虚部:每个128位块中选择索引1、3的元素
__m256 a_imag = _mm256_shuffle_ps(a, a, 0xAA); // 0xAA对应二进制10101010
__m256 b_imag = _mm256_shuffle_ps(b, b, 0xAA);

// 跨128位块合并实部和虚部,仅需两次跨通道操作
__m256 all_real = _mm256_permute2f128_ps(a_real, b_real, 0x20);
__m256 all_imag = _mm256_permute2f128_ps(a_imag, b_imag, 0x20);

优化细节说明

  • 替换高开销指令:原方案的_mm256_permutevar8x32_ps是可变跨通道洗牌,在老AVX2设备(如Haswell之前型号)上延迟高、吞吐量低;优化后用_mm256_shuffle_ps(128位内固定洗牌)替代,该指令硬件支持更成熟,执行效率更高。
  • 减少跨通道操作:原方案共4次跨通道操作,优化后仅保留2次_mm256_permute2f128_ps用于合并两个寄存器的实部/虚部结果,进一步降低整体开销。
  • 结果一致性:优化后的代码最终效果与原方案完全一致,all_real存储所有实部、all_imag存储所有虚部。

内容的提问来源于stack exchange,提问作者Harris M Snyder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 03:25:19