为何无有符号8位整数的NEON饱和舍入加倍乘法intrinsic?8位乘法指令少因何在?
关于ARM NEON 8位整数乘法intrinsic的疑问解答
为何没有类似vqrdmulhq_s16的有符号8位饱和舍入加倍乘法intrinsic?
ARM NEON的intrinsic本质是硬件指令的直接映射,如果硬件指令集里没有对应操作,就不会有对应的intrinsic。vqrdmulhq_s16这类饱和舍入加倍乘法指令,硬件层面只实现了16位及以上位宽的版本,没有针对8位整数的硬件指令,所以自然不存在对应的intrinsic。
8位整数乘法intrinsic数量极少的原因
主要有几点核心因素:
- 硬件支持优先级:早期NEON指令集设计时,8位整数运算更多聚焦在基础乘法(如
vmul_s8)这类高频操作。饱和、舍入这类复杂操作的需求场景当时占比不高,硬件优先级较低。 - 指令编码空间限制:ARM指令的编码空间有限,需要优先分配给更高位宽(如16/32位)或更通用的操作,8位复杂乘法操作没有获得编码资源。
- 替代方案成本低:8位转16位的指令(如
vmovl_s8)开销极低,通过“转高位宽+执行对应操作+转回低位宽”的组合操作,就能实现类似效果,硬件厂商没必要额外增加指令复杂度。
关于你的临时解决方案的评价
你提到的拆分int8x16向量、转成int16x8再执行乘法的方案是完全可行的,这也是当前没有硬件指令时的标准替代思路。举个具体的代码示例:
// 拆分128位int8向量为两个64位int8子向量 int8x8_t vec_a_low = vget_low_s8(vec_a_16); int8x8_t vec_a_high = vget_high_s8(vec_a_16); int8x8_t vec_b_low = vget_low_s8(vec_b_16); int8x8_t vec_b_high = vget_high_s8(vec_b_16); // 有符号扩展为16位向量 int16x8_t vec_a_low_16 = vmovl_s8(vec_a_low); int16x8_t vec_a_high_16 = vmovl_s8(vec_a_high); int16x8_t vec_b_low_16 = vmovl_s8(vec_b_low); int16x8_t vec_b_high_16 = vmovl_s8(vec_b_high); // 执行饱和舍入加倍乘法 int16x8_t res_low_16 = vqrdmulhq_s16(vec_a_low_16, vec_b_low_16); int16x8_t res_high_16 = vqrdmulhq_s16(vec_a_high_16, vec_b_high_16); // 可选:将结果饱和截断回8位并合并为128位向量 int8x8_t res_low = vmovn_s16(res_low_16); int8x8_t res_high = vmovn_s16(res_high_16); int8x16_t res_16 = vcombine_s8(res_low, res_high);
内容的提问来源于stack exchange,提问作者ilp
相关产品推荐
相关产品推荐

