如何用AVX2高效计算交错无符号双字(奇数索引)的横向最大值?
4×256位AVX2向量块奇数索引双字最大值提取优化
问题描述
我们需要处理4个256位YMM寄存器(记为ymm0~ymm3),每个寄存器的双字布局为:
ymmX: a7 a6 a5 a4 a3 a2 a1 a0(从左到右为最高位到最低位双字,对应索引7到0)
目标是从每个YMM寄存器的奇数索引双字(a1/索引1、a3/索引3、a5/索引5、a7/索引7)中提取最大值,最终输出一个256位寄存器,布局为:
0 max3 0 max2 0 max1 0 max0
其中max0是ymm0的目标最大值,max1对应ymm1,以此类推;奇数索引位置填充0。目标CPU具备2个洗牌端口,现有方案使用8条指令,需优化性能或指令数。
优化方案(高吞吐量,适配双洗牌端口)
以下方案利用AVX2指令集,通过并行洗牌和高效横向比较减少延迟,同时压缩指令数:
; 注:ymmzero为预定义的全0256位寄存器,mask为立即数0x07050301(对应双字索引7,5,3,1) ; 阶段1:并行提取所有输入YMM的目标双字(双洗牌端口可并行执行2组vpermd) vpermd ymm4, ymm0, mask vpermd ymm5, ymm1, mask vpermd ymm6, ymm2, mask vpermd ymm7, ymm3, mask ; 阶段2:并行计算横向最大值(单次指令完成两组双字的比较) vpmaxud ymm4, ymm4, ymm4>>64 ; 合并高/低128位对应双字,得到max(a7,a3)、max(a5,a1) vpmaxud ymm5, ymm5, ymm5>>64 vpmaxud ymm6, ymm6, ymm6>>64 vpmaxud ymm7, ymm7, ymm7>>64 vpmaxud ymm4, ymm4, ymm4>>32 ; 最终得到每个YMM的最大值,存于低双字 vpmaxud ymm5, ymm5, ymm5>>32 vpmaxud ymm6, ymm6, ymm6>>32 vpmaxud ymm7, ymm7, ymm7>>32 ; 阶段3:合并结果到目标布局(仅2条指令完成排列) vpunpckldq ymm0, ymm4, ymmzero ; ymm0低128位:0, max0, 0, max1 vpunpckldq ymm1, ymm6, ymmzero ; ymm1低128位:0, max2, 0, max3 vperm2i128 ymm0, ymm0, ymm1, 0x20 ; 合并高/低128位,得到目标布局
优化点说明
- 并行洗牌:借助双洗牌端口,4条
vpermd可分为两组并行执行,大幅降低洗牌阶段的总延迟。 - 高效横向比较:通过移位+比较的组合,仅用2条指令完成单个YMM寄存器4个双字的最大值计算,避免冗余操作。
- 紧凑合并:使用
vpunpckldq和vperm2i128仅用2条指令完成4个最大值的布局排列,减少合并阶段的指令开销。
有符号整数适配
若处理的是有符号32位整数,只需将上述代码中的vpmaxud替换为vpmaxsd即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Akon
相关产品推荐
相关产品推荐

