#simd #stable #channel #simulated #effort #packed-simd #f64x2

simulated_packed_simd

稳定通道的模拟SIMD。使 packed_simd 包在稳定通道上工作的努力

1 个不稳定版本

0.0.1 2020年4月16日

#5#模拟

MIT/Apache

36KB
639

ssimd

这是对未维护的 ssimd 包的分支,目标是使其与 packed_simd 兼容。

在Rust稳定通道上的模拟SIMD。这是使 packed-simd 包 在稳定通道上工作的努力。这项工作基于众所周知的方法:自动向量化。然而,在这个包中,我试图提供一个尽可能接近 simd 包的API。虽然自动向量化似乎是一个运气,但通过以下简单技巧,我已经在大多数情况下使自动向量化成功。

注意

为了使大多数情况下自动向量化成功,请启用BB优化器

https://llvm.net.cn/docs/Vectorizers.html#the-slp-vectorizer

对于Rust,您可以通过以下构建命令构建项目来启用BB优化器

RUSTFLAGS="-C llvm-args=--vectorize-slp -C target-cpu=native" cargo build --release

示例

让我们从一个非常简单的例子开始

extern crate ssimd;
use ssimd::f64x2;

#[inline(never)]
fn test_simd(a : f64x2, b: f64x2) {    
    let c = a + b;
    println!("{:?}", c);
}
fn main() {
    let a = f64x2::new(1.0, 1.0);
    let b = f64x2::new(2.0, 3.0);
    test_simd(a, b);
}

当编译为llvm-ir代码时,您将在函数 "test_simd" 中看到这些指令

      %7 = fadd <2 x double> %4, %6
      store <2 x double> %7, <2 x double>* %c, align 16

以及等效的汇编代码

    addpd    %xmm0, %xmm2
    movapd    %xmm2, 16(%rsp)

在这种情况下,即使使用默认的构建命令,LLVM也可以成功向量化代码。

让我们尝试一个更复杂的例子

extern crate ssimd;
use std::io::{self, BufRead};
use ssimd::f64x2;

fn test_simd(i : i32) {
    let a = f64x2::new((i + 1) as f64, (i + 2) as f64);
    let b = f64x2::new((i + 3) as f64, (i + 3) as f64);
    let c = a + b;
    println!("{:?}", c);
}

fn main() {
    let stdin = io::stdin();
    let mut line = String::new();
    stdin.lock().read_line(&mut line).unwrap();
    let i : i32 = line.trim().parse().unwrap_or(0);

    test_simd(i);
}

函数 "test_simd" 中的 llvm-ir 代码

      %104 = bitcast %"ssimd::f64x2"* %c.i to i8*
      call void @llvm.lifetime.start(i64 16, i8* nonnull %104)
      %105 = fadd double %99, %103
      %106 = fadd double %101, %103

以及汇编代码

    cvtsi2sdl    %ecx, %xmm2
    addsd    %xmm2, %xmm0
    addsd    %xmm2, %xmm1

所以当在函数内部插入整数到浮点转换时,LLVM无法向量化代码。但是,如果启用BB优化器,您将看到以下 llvm-ir 代码

        %109 = fadd <2 x double> %108, %106
        store <2 x double> %109, <2 x double>* %c.i, align 16

以及汇编代码

        addpd    %xmm2, %xmm0
        movapd    %xmm0, 96(%rsp)

因此代码成功向量化。

您可以在 "examples" 文件夹中看到更多示例。这些示例是从 simd 包 移植到稳定通道的。几乎对原始代码没有进行修改。对于这些示例,有些可能在默认构建命令下无法自动向量化。然而,当启用BB优化器时,所有示例都成功向量化。您可以用自己的示例尝试。

AVX指令

某些机器上不支持AVX指令。如果您想使用内联方法(例如在simd crate中)使用AVX指令,您需要使用Rust的"target_feature"属性来检测机器是否支持这些指令。您还需要提供一个后备函数方法,以防AVX指令不可用。然而,如果您使用自动向量化,您只需要提供一个函数方法,因为LLVM将为每个机器配置生成适当的指令。

考虑以下示例

extern crate ssimd;
use ssimd::f64x4;

#[inline(never)]
fn test_simd(a : f64x4, b: f64x4) {
    let c = a + b;
    println!("{:?}", c);
}
fn main() {
    let a = f64x4::new(1.0, 1.0, 1.0, 1.0);
    let b = f64x4::new(2.0, 3.0, 4.0, 5.0);
    test_simd(a, b);
}

在没有AVX指令的机器上,LLVM将生成以下代码

	addpd	%xmm0, %xmm2
	addpd	%xmm1, %xmm3
	movapd	%xmm2, 64(%rsp)
	movapd	%xmm3, 80(%rsp)
 

在支持AVX指令的机器上,LLVM将生成以下代码

	vaddpd	(%rsi), %ymm0, %ymm0
	vmovapd	%ymm0, 64(%rsp)

所以所有的工作都将自动为您完成。

无运行时依赖