使用SSE比较时出现异常行为,代码无报错但逻辑不符
嘿,我来帮你揪出这个SSE指令的异常问题!从你给出的代码片段来看,大概率是这几个常见坑导致的,咱们一个个说:
1. SSE比较指令的结果不是你要的1/0
你可能直接把SSE比较指令的结果存进dst了,但要注意:比如_mm_cmpeq_epi8这类比较指令,返回的每个字节是0xFF(表示条件成立)或者0x00(条件不成立),而不是你需要的0x01和0x00。如果直接存这个结果,得到的就是255而非1,自然会出现异常行为。
解决办法很简单,把0xFF转换成0x01就行——用你已经定义好的v_one向量和比较结果做按位与:
// 假设你在循环里加载了源向量 __m128i v_src = _mm_loadu_si128((__m128i*)&src[i]); // 比较:相等为0xFF,不等为0x00 __m128i v_compare = _mm_cmpeq_epi8(v_src, v_value); // 把0xFF转成0x01,0x00保持不变 __m128i v_result = _mm_and_si128(v_compare, v_one); // 存入目标缓冲区 _mm_storeu_si128((__m128i*)&dst[i], v_result);
2. 内存地址未对齐
SSE的_mm_load_si128和_mm_store_si128要求内存地址是16字节对齐的,如果你的src或dst缓冲区没有满足这个条件,可能会出现隐性的崩溃、结果乱码这类异常。
如果没办法修改内存分配逻辑(比如用_mm_malloc或aligned_alloc做对齐分配),就换成支持非对齐操作的指令:_mm_loadu_si128和_mm_storeu_si128(后缀的u代表unaligned),性能虽然稍差,但能避免对齐问题。
3. 循环边界没处理剩余像素
如果你的图像总像素数(swidth * sheight)不是16的整数倍,主循环处理完所有16字节块后,剩下的不足16个像素会被忽略,这部分的结果自然是错的。
记得在主循环结束后,用普通标量循环处理剩余像素:
int32 total_pixels = swidth * sheight; int32 i; // 处理16字节对齐的块 for (i = 0; i <= total_pixels - 16; i += 16) { // 上面的SSE处理代码 } // 处理剩下的不足16个像素 for (; i < total_pixels; ++i) { dst[i] = (src[i] == value) ? 1 : 0; }
额外小检查
你代码里用了SHOW宏输出向量值,一定要确认v_one的每个字节都是0x01,v_value的每个字节都是传入的value值——确保_mm_set1_epi8的初始化是正确的,别在向量初始化这一步就出问题了。
内容的提问来源于stack exchange,提问作者baptiste

