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

寻找实现__m128i中int16_t有符号乘扩展为int32_t的SIMD内在函数

解决方案

针对你需要将两个__m128i寄存器中的8对int16_t元素分别相乘,得到8个int32_t结果并拆分到两个__m128i寄存器的需求,可以通过以下两种方式实现:

方法一:使用SSE4.1及以上指令集(推荐)

利用_mm_unpacklo_epi16/_mm_unpackhi_epi16将16位元素符号扩展为32位,再通过_mm_mullo_epi32完成32位乘法并保留低32位结果(正好对应int16_t相乘的int32_t结果)。

#include <immintrin.h>

__m128i a = {a0, a1, a2, a3, a4, a5, a6, a7}; // 存储8个int16_t
__m128i b = {b0, b1, b2, b3, b4, b5, b6, b7};

// 将a的低4个int16_t符号扩展为int32_t,存入a_low的4个32位元素
__m128i a_low = _mm_unpacklo_epi16(a, _mm_setzero_si128());
// 将a的高4个int16_t符号扩展为int32_t,存入a_high的4个32位元素
__m128i a_high = _mm_unpackhi_epi16(a, _mm_setzero_si128());

// 对b执行同样的扩展操作
__m128i b_low = _mm_unpacklo_epi16(b, _mm_setzero_si128());
__m128i b_high = _mm_unpackhi_epi16(b, _mm_setzero_si128());

// 对应位置32位相乘,保留低32位(即int16_t相乘的int32_t结果)
__m128i c0 = _mm_mullo_epi32(a_low, b_low); // {a0*b0, a1*b1, a2*b2, a3*b3}
__m128i c1 = _mm_mullo_epi32(a_high, b_high); // {a4*b4, a5*b5, a6*b6, a7*b7}

方法二:兼容SSE2指令集

如果环境不支持SSE4.1,可以借助_mm_madd_epi16(乘加指令),通过构造掩码将加法项置0,从而得到单独的乘积结果。

#include <immintrin.h>

__m128i a = {a0, a1, a2, a3, a4, a5, a6, a7};
__m128i b = {b0, b1, b2, b3, b4, b5, b6, b7};

// 构造掩码:提取b中索引0/2/4/6的元素,其余位置置0
__m128i mask_odd = _mm_setr_epi16(0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0);
__m128i b_odd = _mm_and_si128(b, mask_odd);
// 构造掩码:提取b中索引1/3/5/7的元素,其余位置置0
__m128i mask_even = _mm_xor_si128(mask_odd, _mm_set1_epi16(0xFFFF));
__m128i b_even = _mm_and_si128(b, mask_even);

// 乘加操作:因其中一项为0,结果即为单独的乘积
__m128i prod_odd = _mm_madd_epi16(a, b_odd); // {a0*b0, a2*b2, a4*b4, a6*b6}
__m128i prod_even = _mm_madd_epi16(a, b_even); // {a1*b1, a3*b3, a5*b5, a7*b7}

// 交错合并得到最终结果
__m128i c0 = _mm_unpacklo_epi32(prod_odd, prod_even); // {a0*b0, a1*b1, a2*b2, a3*b3}
__m128i c1 = _mm_unpackhi_epi32(prod_odd, prod_even); // {a4*b4, a5*b5, a6*b6, a7*b7}

关键指令说明

  • _mm_unpacklo_epi16/_mm_unpackhi_epi16:将输入寄存器的低/高8字节(4个int16_t)与零寄存器交错,完成有符号16位到32位的扩展。
  • _mm_mullo_epi32:对两个寄存器中的4个32位元素分别相乘,保留低32位结果——由于int16_t乘积最大值(32767*32767=1073676289)小于int32_t上限,低32位就是正确结果。
  • _mm_madd_epi16:先对成对的int16_t元素相乘,再将相邻两个乘积相加;通过掩码将其中一个乘数置0,即可得到单独的乘积。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:35:17