寻找实现__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
相关产品推荐
相关产品推荐

