#simd #wide #macro

slices_dispatch_wide

一个宏,用于通过使用 wide 包进行 SIMD 操作,将向量化数学操作调度到切片上

2 个版本

0.1.1 2022 年 7 月 3 日
0.1.0 2022 年 7 月 3 日

#1318 in 硬件支持

MIT OR Apache-2.0 OR Zlib

9KB
69

slices_dispatch_wide!

Crates.io docs.rs Crates.io Crates.io


一个宏,用于通过使用 wide 包进行 SIMD 操作,将向量化数学操作调度到切片上

此库会遍历切片的块,将它们转换为来自 wide 包的类型,并在这些块和剩余的标量元素上调度一些数学操作。此库并非在所有情况下都适用,不会对对齐进行特殊处理,而且可能无法胜过最佳的可能手动调整的 SIMD 代码。尽管如此,如果它适用于您的用例,它将使您的生活更加轻松。

此库最有用的情况是

  • 您需要在今天的稳定 Rust 上执行 SIMD 数学操作(例如 sqrtlogexp 等)。
  • 您不想引入非 Rust 库或使您的构建过程复杂化以执行此操作。
  • 您需要同时迭代长度相同的多个切片,并且至少修改其中一个。
  • 您不想重复自己或编写样板代码。
  • 您不需要可变通道宽度。

示例

use slices_dispatch_wide::*;

let mut a = [1.0_f64, 2.0, 3.0, 4.0, 5.0, 6.0];
let b = [2.0_f64, 2.0, 2.0, 2.0, 2.0, 2.0];

// Dispatches using chunks/SIMD types of width 4
slices_dispatch_wide!(4, |a => a mut: f64, b => b: f64| {
    // We can mutate the slices when the mut keyword is specified as it is above
    a += b;
});
// Notice that the number of elements is not a multiple of the SIMD width, the remainder is
// taken care of with scalar operations
assert_eq!(a, [3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);

// We can also do some fancier math operations in place
slices_dispatch_wide!(2, |a => a mut: f64| {
    a = a.powf(2.0);
});
assert_eq!(a, [9.0, 16.0, 25.0, 36.0, 49.0, 64.0]);

// You can assign different names to the elements from the slices you use
// And you can mutate multiple variables at the same time
let mut some_container = ([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], "test", 0);
let mut c = [4.0, 2.0, 1.0, 0.0, 1.0, 2.0];

slices_dispatch_wide!(4, |some_container.0 => sc mut: f64, c => d mut: f64| {
    sc += d;
    d += sc;
});
assert_eq!(some_container.0, [5.0, 4.0, 4.0, 4.0, 6.0, 8.0]);
assert_eq!(c, [9.0, 6.0, 5.0, 4.0, 7.0, 10.0]);

// If you need to get the result in a new array/vector, you can pre-allocate it
let mut d = [0.0; 6];
slices_dispatch_wide!(4, |some_container.0 => sc: f64, d => d mut: f64| {
    d = 2.0 * sc;
});
assert_eq!(d, [10.0, 8.0, 8.0, 8.0, 12.0, 16.0]);

注意,如果切片长度不匹配,此宏将引发恐慌

// This example will panic because the lengths are different

use slices_dispatch_wide::*;

let a = [0u32];
let b = [0u32, 1];
slices_dispatch_wide!(8, |a => a: u32, b => b: u32| {});

并且宽度必须是字面量

// This example will not compile because the width is not a literal

use slices_dispatch_wide::*;

let a = [0u32];
let b = [0u32];
slices_dispatch_wide!(4 + 4, |a => a: u32, b => b: u32| {});

注意事项

  • 使用的 SIMD 类型(每个切片使用的通道宽度和标量类型的组合)必须在 wide 包中存在。
  • 块中的代码必须在迭代变量是给定的标量类型或相应的 SIMD 类型时有效。

许可证

在任何以下许可证下授权

供您选择。

依赖项

~1.5MB
约~30K SLoC