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

如何在不使用AVX-512的前提下通过AVX实现int64转int32

问题:无AVX-512环境下__m256i(4个int64)转__m128i(4个int32)的最优实现

我需要将存储了4个long(64位)的寄存器转换/打包为4个int(32位),也就是将int64类型的__m256i转换为int32类型的__m128i。
我当前环境不支持AVX-512,因此无法使用如下内置函数:

__m256i n;
__m128i r128i = _mm256_cvtepi64_epi32( n );

请问有没有比下述两种方案更优的替代实现?

现有方案1:丢失向量化的落地方案

__m256i n;
alignas(32) int64_t temp[4];
_mm256_store_si256((__m256i*)temp, n);
int32_t a = (int32_t)temp[0];
int32_t b = (int32_t)temp[1];
int32_t c = (int32_t)temp[2];
int32_t d = (int32_t)temp[3];
__m128i r128i = _mm_set_epi32(a, b, c, d);

现有方案2:错误打包为16位整数的方案

__m128i lo_lane = _mm256_castsi256_si128(n);
__m128i hi_lane = _mm256_extracti128_si256(n, 1);
__m128i r128i = _mm_packus_epi32(lo_lane, hi_lane);

答案

以下两种纯向量化实现均无内存访问操作,性能远优于现有落地方案,可根据转换逻辑选择:

方案A:直接截断低32位(性能最优,仅2条指令)

如果业务逻辑只需要取每个int64的低32位,不需要做范围饱和处理,优先用这个方案:

// 按索引提取4个int64的低32位,放到__m256i的低128位区域
__m256i perm = _mm256_permutevar8x32_epi32(n, _mm256_setr_epi32(0, 2, 4, 6, 0, 0, 0, 0));
// 直接取低128位即为目标结果
__m128i res = _mm256_castsi256_si128(perm);

方案B:有符号饱和转换(和AVX-512原生函数行为完全对齐)

如果需要和_mm256_cvtepi64_epi32的行为一致,超出int32范围的数值自动饱和到INT32_MAX/INT32_MIN,用这个方案:

// 拆分256位寄存器的高低128位lane
__m128i lo = _mm256_castsi256_si128(n);
__m128i hi = _mm256_extracti128_si256(n, 1);
// 分别对每个lane的两个int64做饱和转换、调整元素顺序
lo = _mm_shuffle_epi32(_mm_packs_epi32(lo, lo), _MM_SHUFFLE(3, 1, 2, 0));
hi = _mm_shuffle_epi32(_mm_packs_epi32(hi, hi), _MM_SHUFFLE(3, 1, 2, 0));
// 合并两个lane的结果得到最终的4个连续int32
__m128i res = _mm_unpacklo_epi64(lo, hi);

原有方案的问题说明

  1. 落地方案:存在store-to-load转发延迟,至少需要10个时钟周期,且会占用内存带宽,在循环逻辑中性能会下降3~4倍。
  2. 错误打包方案:_mm_packus_epi32的作用是将2个128位寄存器的8个int32饱和转换为8个uint16,输出元素位宽为16位,完全不符合32位输出的需求。

内容的提问来源于stack exchange,提问作者arkan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:27:04