如何用Intel intrinsics高效合并两__m256d低3元素与标量为__m512d?
高效实现两个__m256d与标量合并为__m512d
首先需要明确:_mm256_set_pd是按高位到低位的顺序初始化向量元素的,你当前定义的a = _mm256_set_pd(1, 2, 3, 0)实际生成的向量元素(从低地址到高地址,即索引0到3)是[0, 3, 2, 1],而非直觉中的[1,2,3,0]。如果要按参数顺序初始化向量,应该用_mm256_setr_pd(1,2,3,0)(r代表"reverse",参数顺序对应向量的低到高位元素)。
下面分两种情况给出高效实现:
情况1:保留你当前的_mm256_set_pd定义(元素逆序)
先将两个__m256d的高3个目标元素重排到向量低3位,再合并为__m512d并插入标量:
#include <immintrin.h> int main() { __m256d a = _mm256_set_pd(1, 2, 3, 0); __m256d b = _mm256_set_pd(4, 5, 6, 0); double c = 7; // 重排a的元素:将原高3位(1,2,3)移到低3位,原低位0保留在第3位 __m256d a_perm = _mm256_permute4x64_pd(a, 0b00011011); // 结果:[1,2,3,0] // 同理重排b __m256d b_perm = _mm256_permute4x64_pd(b, 0b00011011); // 结果:[4,5,6,0] // 拼接两个256位向量,此时d的元素为[1,2,3,0,4,5,6,0] __m512d d = _mm512_set_m256d(b_perm, a_perm); // 将索引4-6的元素左移一位覆盖索引3-5,再插入c到索引6 d = _mm512_mask_permutex_pd(d, 0b00111000, d, 0b00000110); d = _mm512_mask_insert_pd(d, 0b01000000, d, c, 6); // 最终d的元素为:[1,2,3,4,5,6,7,0] return 0; }
情况2:改用_mm256_setr_pd按顺序初始化(更符合直觉)
调整初始化方式后,实现会更简洁:
#include <immintrin.h> int main() { __m256d a = _mm256_setr_pd(1, 2, 3, 0); // 元素顺序:[1,2,3,0] __m256d b = _mm256_setr_pd(4, 5, 6, 0); // 元素顺序:[4,5,6,0] double c = 7; // 拼接两个256位向量,得到[1,2,3,0,4,5,6,0] __m512d d = _mm512_set_m256d(b, a); // 左移索引4-6的元素到3-5,插入c到索引6 d = _mm512_mask_permutex_pd(d, 0b00111000, d, 0b00000110); d = _mm512_mask_insert_pd(d, 0b01000000, d, c, 6); // 最终d的元素为:[1,2,3,4,5,6,7,0] return 0; }
效率说明
- 使用
_mm256_permute4x64_pd和_mm512_mask_permutex_pd这类向量重排指令,避免了多次标量提取/插入的开销,能充分利用AVX512的向量并行能力。 - 主流编译器(GCC/Clang/MSVC)会根据目标CPU架构优化指令序列,最终生成的机器码效率接近最优。
内容的提问来源于stack exchange,提问作者CaG
相关产品推荐
相关产品推荐

