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

两个卷积循环是否等价?SIMD优化后结果不符问题咨询

卷积SIMD优化后结果不一致的问题分析

我正在处理卷积运算,为提升执行速度采用SIMD指令同时执行两次乘法,将一次结果存入64位变量的高32位,另一次存入低32位,但优化后的新代码运行结果与原代码不一致。

原代码实现

int32_t v32;
int16_t arr_2[1024];
int16_t data[96];
int32_t accu;
...
for(int j=0; j<INPUT_F; j++){
  v32 = arr_2[l*OUT_F+j] * data[k*K*INPUT_F+(l-i+K/2)*INPUT_F+j];
  accu += v32;
}
...

优化后的代码实现

uint64_t v64; 
int16_t arr_2[1024];
int16_t data[96];
int32_t accu;
...
for(int j=0; j<INPUT_F/2; j++){
  v64 = __mul(arr_2[l*OUT_F+2*j], data[k*K*INPUT_F+(l-i+K/2)*INPUT_F+2*j]); // 用SIMD指令执行数组中连续两个值的乘法
  accu += ((int32_t)(v64 & 0xFFFFFFFF)); // 第一个结果
  accu += ((int32_t)((v64 >> 32) & 0xFFFFFFFF)); // 第二个结果
}
...

__mul的定义为uint64_t __mul(uint32_t a, uint32_t b);,尽管操作数是uint32_t,但其会处理内部的两个int16_t值。

除乘法函数外的操作问题分析

你当前的优化代码存在几处明显错误,导致和原代码不等价:

  • 数组索引与参数打包错误:
    原代码每次循环处理一组(arr_2[j], data[j])的乘法,优化后要同时处理(arr_2[2j], data[2j])和(arr_2[2j+1], data[2j+1])两组。但你的代码只将arr_2[2j]和data[2j]传给__mul,没有把连续的第二个元素(2j+1位置)打包到uint32_t参数中。
    按照__mul的设计(处理参数内部的两个int16_t),你需要把两个连续的int16_t打包成一个uint32_t:比如将arr_2[2j]存在参数a的低16位,arr_2[2j+1]存在高16位;同理data[2j]和data[2j+1]打包到参数b中。当前的参数传递只传入了单个int16_t(会被符号扩展为32位,高16位不是第二个元素的值),导致__mul处理的是错误的操作数。

  • 循环次数遗漏问题:
    如果INPUT_F是奇数,原循环执行INPUT_F次,而优化后的循环执行INPUT_F/2次(整数除法),会直接漏掉最后一组j=INPUT_F-1的乘法操作,导致累加结果少了一个值。必须确保INPUT_F是偶数,或者在循环结束后单独处理剩余的一次乘法。

  • 符号转换的潜在风险:
    原代码中int16_t相乘得到的是有符号int32_t结果。优化后你将uint64_t的低/高32位直接强转为int32_t,若__mul是将有符号的int32_t结果以补码形式存储在uint64_t中,多数编译器能正确完成无符号到有符号的转换,但这属于实现定义行为。更稳妥的方式是先将对应32位区域视为有符号数,比如用*(int32_t*)&v64取低32位,*(int32_t*)((uint8_t*)&v64 + 4)取高32位(需注意字节序,若SIMD指令是小端存储则正确)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 16:22:12