如何让Rust编译器生成AVX2指令?我的分块函数为何无宽乘法?
为什么手动分块的mul2函数没有生成AVX2宽乘法指令?
你写的两个函数逻辑本质完全一致:
fn mul1(xs: &[i32], ys: &[i32]) -> Vec<i32> { // Assuming xs.len() == ys.len() xs.iter().zip(ys.iter()).map(|(x, y)| x * y).collect() } fn mul2(xs: &[i32], ys: &[i32]) -> Vec<i32> { const CHUNK_SIZE: usize = 8; // Assuming xs.len() == ys.len() and xs.len() % CHUNK_SIZE == 0 let chunks = xs.chunks_exact(CHUNK_SIZE).zip(ys.chunks_exact(CHUNK_SIZE)); let result_chunks = chunks.map(|(c1, c2)| c1.into_iter().zip(c2.into_iter()).map(|(x, y)| x * y)); result_chunks.flatten().collect() }
问题出在哪?
mul2只是把数组做了表面上的分块,但内部依然是逐个元素遍历相乘,和mul1的执行逻辑没有任何区别。Rust编译器的自动向量化优化不需要你手动拆分数组,它会自行识别连续的元素级运算并生成SIMD指令;手动分块的操作完全是多余的,不会给编译器提供额外的优化线索。
怎么真正利用AVX2指令?
如果要手动控制AVX2的使用,不能依赖普通迭代器,需要直接使用AVX2的内在函数(intrinsics),或者借助SIMD相关库。以下是用标准库intrinsics实现的示例:
use std::arch::x86_64::*; fn mul_avx2(xs: &[i32], ys: &[i32]) -> Vec<i32> { assert_eq!(xs.len(), ys.len()); assert_eq!(xs.len() % 8, 0); let mut result = vec![0; xs.len()]; unsafe { for i in (0..xs.len()).step_by(8) { // 加载8个i32到AVX2寄存器 let x = _mm256_loadu_si256(xs.as_ptr().add(i) as *const __m256i); let y = _mm256_loadu_si256(ys.as_ptr().add(i) as *const __m256i); // 批量乘法:8个i32同时相乘 let mul_result = _mm256_mullo_epi32(x, y); // 将结果写回内存 _mm256_storeu_si256(result.as_mut_ptr().add(i) as *mut __m256i, mul_result); } } result }
补充:关于自动向量化
你的mul1函数在开启-O2或-O3优化后,编译器会自动生成AVX2指令。查看汇编时要确保开启了优化模式,Debug模式下编译器不会进行向量化这类激进优化。
内容的提问来源于stack exchange,提问作者scasci
相关产品推荐
相关产品推荐

