使用GCC编译sum_of_squares函数返回0,是否为GCC Bug?
问题:GCC编译后sum_of_squares函数返回0,是代码错误还是编译器Bug?
用户代码如下:
#include <stdio.h> #include <x86intrin.h> int sum_of_squares(int x[], int n) { int sum = 0; __m256i sum8 = _mm256_set1_epi32(0); for (int i = 0; i < n; i += 8) { __m256i x8 = _mm256_load_si256((__m256i *)&x[i]); x8 = _mm256_mul_epi32(x8, x8); sum8 = _mm256_add_epi32(x8, sum8); } int *_sum = (int *)&sum8; for (int i = 0; i < 8; i++) sum += _sum[i]; return sum; } int main() { _Alignas(32) int x[16]; for (int i = 0; i < 15; i++) { x[i] = i; } printf("%d", sum_of_squares(x, 16)); }
问题根源:误用AVX乘法指令
这不是GCC的Bug,是代码里错误使用了AVX指令:
_mm256_mul_epi32的行为并非对每个32位元素单独平方,而是将寄存器中8个32位整数两两配对相乘,每对生成一个64位结果。也就是说,_mm256_mul_epi32(x8, x8)会把x8中的[a0,a1,a2,a3,a4,a5,a6,a7]转换成[a0*a1(64位), a2*a3(64位), a4*a5(64位), a6*a7(64位)],寄存器里实际是4个64位值,而非8个32位值。- 后续用
_mm256_add_epi32累加时,会把64位值拆成两个32位部分单独相加,导致高位的乘积结果被错误拆分;最后直接把sum8当成8个int读取时,读到的是64位值的高32位(测试用例中数值很小,高32位为0)和低32位的错误组合,最终求和结果为0。
修正方案
如果你需要对每个32位元素单独平方并累加,应该使用_mm256_mullo_epi32指令——它会对每个32位元素执行乘法,保留结果的低32位,输出仍为8个32位整数,完全符合需求。
修正后的核心代码部分:
// 替换原来的_mm256_mul_epi32调用 x8 = _mm256_mullo_epi32(x8, x8); sum8 = _mm256_add_epi32(x8, sum8);
修正后运行代码,会得到正确的平方和结果(测试用例中x[0]到x[15]的平方和为1240)。
内容的提问来源于stack exchange,提问作者Sai Charan Marrivada
相关产品推荐
相关产品推荐

