Arrays 这是从SIMD数组到常规数字类型的转换吗?

Arrays 这是从SIMD数组到常规数字类型的转换吗?,arrays,rust,simd,reinterpret-cast,Arrays,Rust,Simd,Reinterpret Cast,我有一个浮点值数组,我需要做一些易于向量化的操作,比如取所有浮点值的和,然后除以这些和。我还需要访问(主要是读取)数组的各个元素。我想我可以使用SIMD类型来启用数组的矢量化。每当我需要对数组的各个元素执行很多操作时,我都会将数组转换为对常规浮点值数组的引用,并访问该引用,如下所示: extern crate simd; use simd::x86::avx::f32x8; fn main() { let values8: [f32x8; 100] = [f32x8::splat(1

我有一个浮点值数组,我需要做一些易于向量化的操作,比如取所有浮点值的和,然后除以这些和。我还需要访问(主要是读取)数组的各个元素。我想我可以使用SIMD类型来启用数组的矢量化。每当我需要对数组的各个元素执行很多操作时,我都会将数组转换为对常规浮点值数组的引用,并访问该引用,如下所示:

extern crate simd;

use simd::x86::avx::f32x8;

fn main() {
    let values8: [f32x8; 100] = [f32x8::splat(1.1); 100];
    let values: &[f32; 800] = unsafe { std::mem::transmute(&values8) };

    println!("{}", values[333]);
}
这是编译好的,似乎工作得很好。但我担心这是未定义的行为,因为:

非repr(C)类型之间的转换是UB

我认为SIMD类型(如
SIMD::x86::avx::f32x8
)是
repr(SIMD)
,而
[f32;800]
也不是
repr(C)


我知道我可以在SIMD类型上使用
extract
方法来获取这些单独的浮点值,但是使用前面提到的transmute-to-a-regular-array方案会使代码更简单。

如果没有任何特定的保证(我找不到),我认为您无法得出这样的结论:它是安全的

事实上,如上所述,由于一个稍微不同的原因,它绝对是不安全的;您已清洗了对
值8
的引用,借阅检查器未跟踪该引用;它让我这样做:

extern crate simd;

use simd::f32x4;

fn main() {
    let mut values8: [f32x4; 100] = [f32x4::splat(1.1); 100];
    let values: &[f32; 400] = unsafe { std::mem::transmute(&values8) };

    let t = &mut values8[4];
    println!("{}", values[333]); // but there's a mutable reference!
}
早期的定义是

对repr(simd)类型的字段进行内部引用是非法的,因为布尔的表示可能需要更改,因此布尔是位压缩的。提供SIMD支持的官方外部库将具有私有字段,因此通常无法观察到

这显然禁止将simd类型转换为数组

实际的RFC,很明显,你可以引用内部的东西。RFC还规定布局和路线取决于平台

由于我所知道的所有平台都不会向普通的simd类型(如
f32x8
)添加填充,因此您可以假设
f32x8
的布局与
[f32;8]
的布局“相同”,因为它包含8个紧紧封装在32字节内存中的
f32
。但命令可能是任意的


“非repr(C)类型之间的转换是UB”我认为simd类型(如simd::x86::avx::f32x8)是repr(simd),我认为[f32;800]也不是repr(C)

从技术上讲,您既不是在转换
repr(simd)
类型,也不是在转换
[f32;800]
,而是在将一个引用转换为另一个引用,但结果是相同的


正如@Chris Emerson所指出的,您的示例中的不安全性来自生命链的断裂。要恢复这一点,请创建一个抽象边界:

fn simd_slice(simd: &[f32x8; 100]) -> &[f32; 800] {
    unsafe { &*(simd as *const [f32x8; 100] as *const [f32; 800]) }
}

我很想知道为什么
f32x8
没有像Vec那样实现
Borrow
,这将是一个折衷方案。也许布局/顺序不能保证兼容。但我最感兴趣的是,执行转换是否已经是未定义的行为,或者如果以后以内存安全的方式使用生成的引用变量,执行转换是否可以。仅以内存安全的方式使用它并不能保证内存安全,您需要一个抽象边界。因此,如果您将所有不安全因素转储到一个函数中,那么如果您正确设置了生存时间,您就永远不会在该函数之外错误地使用它。“但是顺序可能是任意的。”这是否意味着(在我的示例中)
值8[0]。摘录(5)
不一定返回与
值[5]
相同的值?是的,这就是那句话的意思。顺序是由平台定义的,因此您可能需要了解llvm对simd的作用,或者您的体系结构对simd的作用。