如何以最快且可预测的方式实现16个单字节数组对应元素相加?
16字节数组逐元素相加的优化实现疑问
我有两个无重叠的16字节数组a和b,需要将每个b[i]与对应的a[i]相加,且已知每个相加结果都能容纳在单个字节内(这点至关重要)。
参考实现
void add16_reference (uint8_t *as, uint8_t *bs) { for (auto i = 0; i < 16; i++) { as[i] += bs[i]; } }
当前最优实现
我尝试了多种重写方式,目前找到的最优实现如下:
typedef unsigned __int128 uint128_t; void add16_v3 (uint8_t *as, uint8_t *bs) { uint128_t a, b, s; std::memcpy(&a, as, 16); std::memcpy(&b, bs, 16); s = a + b; std::memcpy(as, &s, 16); }
GCC和Clang都能把这段代码编译成2条mov指令和2条add指令,效果不错,但我想知道是否存在更优的实现方式。
遇到的问题与思考
- 由于已知单个相加结果不会溢出单字节,我认为可以用一次加法完成操作。
- 观察编译结果发现,编译器有时会生成SIMD指令,有时不会。这点很关键,基准测试显示普通mov/add指令的速度约为SIMD的8倍。此外,无法确保编译器始终采用某种优化方式——比如某个版本在本地编译出mov/add指令,但在基准测试环境中却生成了SIMD指令。
- 我尝试用
reinterpret_cast替代memcpy,但无论怎么调整都会生成类SIMD指令;另外在C语言的参考实现中给as和bs添加restrict关键字后,编译器始终会生成SIMD指令(这符合预期)。
核心疑问
综合以上情况,是否存在更快、更简洁、更可预测的方式来实现这些数字的相加?
编辑说明:感谢@Jan指出原基准测试有误,更新后的版本可能正确。
内容的提问来源于stack exchange,提问作者adrianton3
相关产品推荐
相关产品推荐

