\_mm256\_load\_ps 要求32字节内存对齐,否则可能崩溃或出错;需用 aligned\_alloc 或 \_mm\_malloc 分配,或加 \_\_attribute\_\_((aligned(32)));非对齐用 \_mm256\_loadu\_ps 但性能降10–30%。

用 _mm256_load_ps 读数据前,必须保证内存对齐
AVX2 的 256 位加载指令(如 _mm256_load_ps)要求地址是 32 字节对齐的,否则运行时触发 segmentation fault 或静默错误(尤其在某些 CPU 上)。这不是编译期能检查的问题,而是典型的“跑一半崩”陷阱。
- 分配内存时用
aligned_alloc(32, size)(C11)或_mm_malloc(size, 32)(Intel 提供,需配对用_mm_free) - 若从现有数组加载,先用
_mm256_loadu_ps(un-aligned),但性能下降约 10–30%,且可能破坏流水线 - 结构体成员或栈上数组默认不保证对齐,
__attribute__((aligned(32)))可强制,但要同步约束整个访问链路
矩阵乘 c[i][j] += a[i][k] * b[k][j] 不能直接向量化
标准三重循环里,b[k][j] 是按行优先存储却按列访问,造成严重 cache miss;同时 sum 累加存在写后读依赖,编译器很难自动向量化。手动向量化得重构访存模式和累加逻辑。
- 把
b转置成bT,让内层循环变成连续读a[i][k]和bT[j][k] - 用多个
__m256寄存器并行累加多行结果(例如一次算 8 个c[i][j]),避免单寄存器瓶颈 - 内层循环展开 4–8 次,隐藏指令延迟;注意不要过度展开导致寄存器溢出(AVX2 最多 16 个 YMM 寄存器)
Clang/GCC 自动向量化失败的常见原因
即使开了 -O3 -mavx2,编译器也常放弃向量化,不是它不行,而是你写的代码“不可信”。
- 指针别名:用
restrict告诉编译器a、b、c不重叠,否则它不敢重排访存顺序 - 循环边界含变量或非 8/16 倍数:用
#pragma omp simd或显式处理尾部(for (i = 0; i ) - 混用 float/double:AVX2 处理 float 用
_mm256_*,double 用_mm256_*_pd,混用会禁用整段向量化
AVX2 矩阵乘实测加速比远低于理论值?查这几个点
256 位宽理论上比标量快 8 倍,实际 3–4 倍已算不错。瓶颈往往不在计算本身,而在数据搬运和调度。
立即学习“C++免费学习笔记(深入)”;
- 用
perf stat -e cycles,instructions,cache-misses看 cache miss rate 是否 >5% —— 高了说明数据没预取或分块太小 - 矩阵维度不是 8/16 对齐时,尾部处理逻辑是否退化成标量?这部分耗时占比可能超预期
- 是否在循环内反复调用
_mm256_set1_ps(x)?应提到循环外,避免重复生成广播常量
真正难的不是写几条 _mm256_add_ps,而是让数据在正确的时间、以正确的布局、落到正确的寄存器里——中间任何一环断掉,SIMD 就变负优化。










