Rust 为什么存储到AVX2 256bit向量和从AVX2 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

当我尝试在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_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
    功能,因此请确保在调用之前进行检查
  • 不值得探究为什么调试版本会给出正确的结果,因为在我的家用计算机上运行它的版本也会给出正确的结果(在某些咒语下)。查看汇编显示,LLVM以这种或那种方式进行了优化,但并不是特别有见地

  • 你确定一个4 i64的数组可以被认为是“由*a指向的256位对齐的内存位置”吗?据我所知,4 i64是i64对齐的即使对齐有问题,其症状是崩溃而不是输出不正确(
    vmovaps
    未对齐的地址会生成错误)看起来像LLVM
    println中的错误!(“{:?}”,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);
    }