Mobile Monitoring Solutions

Search
Close this search box.

Rust 1.27 Adds Support for SIMD

MMS Founder
MMS RSS

Article originally posted on InfoQ. Visit InfoQ

SIMD support is the most notable new feature in Rust 1.27, along with a more explicit syntax for traits.

SIMD support at the language level means developers can express vectorized computations at a higher-level and have a chance at outperforming the compiler when it is not smart enough to apply autovectorization. The following is an example of how you can express a sum of two vectors (or slices) of 16 elements each one byte long (u8). Each slice fits one 128 bit register, so we can put the two slices into two registers and add them in a single CPU instruction using the new std::arch module:

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"),
      target_feature = "avx2"))]
fn foo() {
    #[cfg(target_arch = "x86")]
    use std::arch::x86::_mm256_add_epi64;
    #[cfg(target_arch = "x86_64")]
    use std::arch::x86_64::_mm256_add_epi64;

    unsafe {
        _mm256_add_epi64(...);
    }
}

The snippet above also shows how you can customize your SIMD instructions for specific platforms, since not all platforms your code should be able to run on may support SIMD operations. The first cfg flag will output the following code only for the specified platforms (x86 or x86_64 provided they support AVX2), while the inner cfg flags will choose the right _mm256_add_epi64 instruction for the specific platform.

SIMD support provided by std::arch is only the first step in Rust SIMD support. Indeed, a std::simd module is already planned which should provide higher-level operations. An example of what could be possible in std::simd is given through the faster crate, which allows you to use simd_iter instead of iter, simd_map instead of map, etc., to use SIMD-ified versions of those basic vector operations.

Another new feature of the language aims to make the trait syntax more explicit and make it clearer when a given trait object corresponds to just one pointer or two of them. The basic syntax to represent a trait object is the following:

    Box<Foo>

This syntax hides the fact that when Foo is a structure it will be simply embedded inside Box. On the contrary, it will be allocated on the heap if it is a trait and a pointer to its vtable will be allocated on the stack. This is due to vtables in Rust not being stored with the data, as it happens in C++, but separately. To make things clearer, now Rust supports a new dyn Trait syntax:

    Box<dyn Foo>
    &dyn Foo
    &mut dyn Foo

The old syntax will remain in place and there are no defined plans for its deprecation.

As a final note, the #[must_use] attribute can be now used on functions to make the compiler flag any situation where the return value of such functions is ignored:

#[must_use]
fn double(x: i32) -> i32 {
    2 * x
}

fn main() {
    double(4); // warning: unused return value of `double` which must be used

    let _ = double(4); // (no warning)
}

To read more about Rust 1.27, do not miss the official release notes.

Subscribe for MMS Newsletter

By signing up, you will receive updates about our latest information.

  • This field is for validation purposes and should be left unchanged.