1 个不稳定版本
0.1.0 | 2020年9月7日 |
---|
#28 in #explicit
110KB
3K SLoC
generic-simd
generic-simd提供了编写显式跨平台SIMD操作的安全且惯用的零成本抽象。
许可证
generic-simd以MIT许可证和Apache许可证(版本2.0)的条款进行分发。
有关详细信息,请参阅LICENSE-APACHE和LICENSE-MIT。
lib.rs
:
generic-simd
提供了编写显式跨平台SIMD操作的安全且惯用的零成本抽象。
支持的架构
所有架构都通过标量回退支持,但以下指令集也得到支持
- SSE4.1 (x86/x86-64)
- AVX (x86/x86-64)
- NEON (aarch64,需
nightly
cargo功能) - SIMD128 (wasm32,需
nightly
cargo功能和simd128
目标功能)
各种架构特定类型在arch
模块中可用。
抽象
通过vector
模块中的特性行提供向量抽象。使用这些特性行的泛型能够利用任何支持的指令集。
以下示例执行输入切片的向量加速求和
use generic_simd::{
arch::Token,
dispatch,
scalar::ScalarExt,
slice::SliceExt,
vector::NativeVector,
};
// This function provides a generic implementation for any instruction set.
// Here we use the "native" vector type, i.e. the widest vector directly supported by the
// architecture.
#[inline]
fn sum_impl<T>(token: T, input: &[f32]) -> f32
where
T: Token,
f32: ScalarExt<T> + core::iter::Sum<NativeVector<f32, T>>,
{
// Use aligned loads in this example, which may be better on some architectures.
let (start, vectors, end) = input.align_native(token);
// Sum across the vector lanes, plus the unaligned portions
vectors.iter().copied().sum::<f32>() + start.iter().chain(end).sum::<f32>()
}
// This function selects the best instruction set at runtime.
// The "dispatch" macro compiles this function for each supported architecture.
#[dispatch(token)]
fn sum(input: &[f32]) -> f32 {
sum_impl(token, input)
}
assert_eq!(sum(&[1f32; 10]), 10.);
向量适配器
不同的指令集提供不同宽度的向量,因此提供了适配器来创建特定宽度的向量,而不考虑架构。这些适配器在shim
模块中可用。
例如,以下函数使用4个f64
的数组执行数组数组结构操作,而不考虑指令集
use generic_simd::{
arch::Token,
dispatch,
scalar::Scalar,
slice::Slice,
vector::{Signed, Vector, width},
};
// Equivalent to an array of 4 2-dimensional coordinates,
// but with a vectorizable memory layout.
struct Coordinates {
x: [f64; 4],
y: [f64; 4],
}
// A generic mean implementation for any instruction set.
fn mean_impl<T>(token: T, input: &[Coordinates]) -> (f64, f64)
where
T: Token,
f64: Scalar<T, width::W4>,
<f64 as Scalar<T, width::W4>>::Vector: Signed,
{
let mut xsum = f64::zeroed(token);
let mut ysum = f64::zeroed(token);
for Coordinates { x, y } in input {
// read the arrays into vectors
xsum += x.read(token);
ysum += y.read(token);
}
// sum across the vector lanes
(
xsum.iter().sum::<f64>() / (input.len() * 4) as f64,
ysum.iter().sum::<f64>() / (input.len() * 4) as f64,
)
}
// Selects the best instruction set at runtime.
#[dispatch(token)]
fn mean(input: &[Coordinates]) -> (f64, f64) {
mean_impl(token, input)
}
依赖项
~1.5MB
~36K SLoC