在 Rust 中使用 SIMD 执行矩阵乘积时出现访问冲突

问题描述 投票:0回答:1

我正在为我的 opengl 项目制作自己的 linalg 库,并且正在考虑使用 simd 加速 matmul。

最小可重现示例:

use std::arch::x86_64::*;

#[derive(Debug, Clone, Copy)]
struct Mat4f {pub data: [[f32; 4]; 4]}

#[repr(align(16))]
struct AlignedF32([f32; 4]);

impl Mat4f {
    pub fn new() -> Self {
        Self {data: [[0_f32; 4]; 4]}
    }
}

#[cfg(all(
    any(target_arch = "x86", target_arch = "x86_64"),
    target_feature = "sse"
))]
impl Mat4f {
    pub fn mm_simd(&self, other: &Self) -> Self {
        let a = &self.data; // transposing is omitted here
        let b = &other.data;
        let mut buffer = AlignedF32([0_f32; 4]);
        let mut product: Mat4f = Mat4f::new();
        unsafe {
            for i in 0..4 {
                for j in 0..4 {
                    let m1 = _mm_mul_ps(_mm_load_ps(b[i].as_ptr()), _mm_load_ps(a[j].as_ptr()));
                    let m2 = _mm_hadd_ps(m1, m1);
                    let m3 = _mm_hadd_ps(m2, m2);
                    _mm_store_ps(buffer.0.as_mut_ptr(), m3);
                    product.data[i][j] = buffer.0[0];
                }
            }
        }
        product
    }
}

fn main() {
    let a: Mat4f = Mat4f::new();
    let b: Mat4f = a;
    println!("{:?}", a.mm_simd(&b));
    
    // crashes if you run the following line
    // for i in 0..10{}
}
在循环内、循环之前或循环之后调用

a.mm_simd(&b)
时,会导致访问冲突,抛出 (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
不确定 simd 对于 mat4x4 产品是否真的有必要。但令我困扰的是,一条不执行任何操作的附加行实际上会导致整个系统崩溃。

rust linear-algebra simd intrinsics
1个回答
1
投票
Mat4f

上没有强制对齐,因此使用指向其中包含的切片的参数来调用

_mm_load_ps(b[i].as_ptr())
是无效的,并且会调用 UB。这意味着虽然它
可能
按预期工作,但它也可能会出错或损坏你的记忆。

令我困扰的是,一条不执行任何操作的附加行实际上会导致整个系统崩溃

是的,这就是UB的本质,它可能会受到完全不相关的代码的影响。

© www.soinside.com 2019 - 2024. All rights reserved.