Rust 为什么存储到AVX2 256bit向量和从AVX2 256bit向量加载在调试和发布模式下会产生不同的结果?
当我尝试在AVX2 256bit向量中输入和输出256bit时,在释放模式下没有收到预期的输出Rust 为什么存储到AVX2 256bit向量和从AVX2 256bit向量加载在调试和发布模式下会产生不同的结果?,rust,compiler-optimization,simd,avx2,Rust,Compiler Optimization,Simd,Avx2,当我尝试在AVX2 256bit向量中输入和输出256bit时,在释放模式下没有收到预期的输出 use std::arch::x86_64::*; fn main() { let key = [1u64, 2, 3, 4]; let avxreg = unsafe { _mm256_load_si256(key.as_ptr() as *const __m256i) }; let mut back_key = [0u64; 4]; unsafe { _mm256
use std::arch::x86_64::*;
fn main() {
let key = [1u64, 2, 3, 4];
let avxreg = unsafe { _mm256_load_si256(key.as_ptr() as *const __m256i) };
let mut back_key = [0u64; 4];
unsafe { _mm256_storeu_si256(back_key.as_mut_ptr() as *mut __m256i, avxreg) };
println!("back_key: {:?}", back_key);
}
在调试模式下:
back_键:[1,2,3,4]
在释放模式下:
back_键:[1,2,0,0]
后半部分要么没有加载,要么没有存储,我不知道是哪个
奇怪的是,以本机CPU为目标是可行的。在释放模式下+RUSTFLAGS=“-C目标cpu=native”
back_键:[1,2,3,4]
我甚至试图通过强制对齐来消除Clippy错误,但毫无效果(我不确定下面的代码是否更正确)
#[target_feature(enable = "avx2")]
或者用
RUSTFLAGS="-C target-feature=+avx2" cargo run --release
第一个选项更好,因为它保证函数中使用的SIMD指令得到适当编译,调用方只需在使用调用之前检查其CPU是否具有这些功能即可检测到\u x86\u feature\u!(“avx2”)
。所有这些都有文档记录,但如果编译器可以用“嘿,这个函数使用AVX2指令,但没有用#[target_feature(enable=“AVX2”)]
注释,并且程序没有全局启用AVX2进行编译,那么调用这个函数是未定义的行为”,这将是一件令人惊讶的事情。这会让我省去很多头痛
由于依赖未定义的行为是不好的,我们在操场上的初始程序应该写为:
use std::arch::x86_64::*;
fn main() {
unsafe { run() }
}
#[target_feature(enable = "avx2")]
unsafe fn run() {
let key = [1u64, 2, 3, 4];
let avxreg = _mm256_load_si256(key.as_ptr() as *const __m256i);
let mut back_key = [0u64; 4];
_mm256_storeu_si256(back_key.as_mut_ptr() as *mut __m256i, avxreg);
println!("back_key: {:?}", back_key);
}
一些注意事项:
main
不能是不安全的,因此不能使用target\u功能进行注释,因此有必要提取到另一个函数中
x86_64
CPU具有avx
功能,因此请确保在调用之前进行检查你确定一个4 i64的数组可以被认为是“由*a指向的256位对齐的内存位置”吗?据我所知,4 i64是i64对齐的即使对齐有问题,其症状是崩溃而不是输出不正确(
vmovaps
未对齐的地址会生成错误)看起来像LLVMprintln中的错误!(“{:?}”,avxreg)
允许说,加载
已经是问题所在,使用\u mm256\u loadu\u si256
修复它,但商店仍然会错误地读取输出,看起来我应该将其提取到另一个函数中,并使用\target\u功能(enable=“avx2”)]
。所以我认为这回答了问题2,3,但idk关于我的怀疑是,你可能可以更具体一点。特别是,类似于“您不能从本身未为AVX编译的函数调用ABI依赖于AVX寄存器的函数。”因此,在您的情况下,main
未使用AVX编译,但您调用的是一个例程,其中函数签名中出现了\uum256i
。由于AVX向量不会出现在run
类型中,因此修改后的代码不再执行此操作。
use std::arch::x86_64::*;
fn main() {
unsafe { run() }
}
#[target_feature(enable = "avx2")]
unsafe fn run() {
let key = [1u64, 2, 3, 4];
let avxreg = _mm256_load_si256(key.as_ptr() as *const __m256i);
let mut back_key = [0u64; 4];
_mm256_storeu_si256(back_key.as_mut_ptr() as *mut __m256i, avxreg);
println!("back_key: {:?}", back_key);
}