Expand description
VectorEyes is a (almost entirely) safe and cross-platform wrapper library around vectorized operations.
While a normal add CPU instruction will add two numbers together, a
SIMD/Vectorized add
instruction will perform multiple additions from the same instruction. This will amortize the
per-instruction cost (e.g. of the CPU decoding the instruction) across all the additions of the
single instruction. This can provide large speed boosts on many platforms.
Unfortunately, using these operations require using per-platform unsafe intrinsics. To make this easier, VectorEyes provide safe functions which will function identically on all platforms.
The core of this crate is vector types (such as U64x2). You can think of vectors as arrays
with some extra SIMD operations on top.
Just like arrays vectors have an element type (u64 in the example above), and an element
count, frequently referred to as lanes (2 in the above example).
In fact, you can freely convert between arrays and vectors!
// These two represent the same thing.
let vector_form = U64x2::from([123_u64, 456_u64]);
let array_form: [u64; 2] = vector_form.into();However, the vector form has special SIMD powers! These two functions perform the same operation, but the SIMD variant may1 take better advantage of the CPU hardware.
While normal bog-standard arrays don’t implement the + operator, our vector types do!
Adding two vectors together performs pairwise addition, using (for the vector backends) a
single CPU instruction!
fn double_without_simd(arr: [u64; 2]) -> [u64; 2] {
[arr[0] + arr[0], arr[1] + arr[1]]
}
fn double_with_simd(arr: U64x2) -> U64x2 {
arr + arr
}
assert_eq!(
U64x2::from(double_without_simd([1, 2])),
double_with_simd(U64x2::from([1, 2])),
);The documentation for every method on a vector (e.g. I64x2::and_not) lists the equivalent
scalar code, as well as information on how the operation is implemented on each backend.
§Vector Sizes
There aren’t vector types for every conceivable (type, element count) pair. Instead, we have
vector types that correspond to the vector registers that many CPUs have. Because these
registers are 128- or 256-bits wide, we choose vector types which also have this size. For
example, there’s a U64x2 type and a U32x4 type, since both are 128-bits wide. But
there’s no U32x2 type, because that’d only be 64-bits wide.
§Backends
VectorEyes chooses what backend to execute vector operations with at compile-time.
§AVX2
x86-64 CPUs that support the AVX, AVX2, SSE4.1, AES, SSE4.2, and
PCLMULQDQ features will use the AVX2 backend.
§Neon
This is available on aarch64/arm64 machines with neon and aes features.
§Scalar
This is a fallback implementation that works on all CPUs. It’s not particularly performant.
§Cargo Configuration
If using VectorEyes from the swanky repo, all this configuration has already been done for
you!
§Native CPU Setup
Compile on the machine that you’ll be running your code on, and add the
following to your .cargo/config file:
[build]
rustflags = ["-C", "target-cpu=native", "--cfg=vectoreyes-target-cpu-native"]
rustdocflags = ["-C", "target-cpu=native", "--cfg=vectoreyes-target-cpu-native"]§Specific CPU Selection
If you want to compile for some specific CPU, add the following to your
.cargo/config file:
[build]
rustflags = ["-C", "target-cpu=TARGET", "--cfg=vectoreyes-target-cpu=\"TARGET\""]
rustdocflags = ["-C", "target-cpu=TARGET", "--cfg=vectoreyes-target-cpu=\"TARGET\""]§Maximal Compatibility
If you do not put any of the above in your .cargo/config file,
vectoreyes will always use its scalar backend, which does not use vector
instructions.
§Limitations
VectorEyes was designed around the AVX2 backend. For example, shuffle operations tend to be constrained to 128-bit lanes because that’s how the Intel intrinsics are constrained. As a result, while code that uses VectorEyes might be optimal for an Intel platform, it might not be optimal for an ARM platform with different intrinsics. (This is a limitation, generally, with cross-platform SIMD libraries like VectorEyes.)
In addition, many SIMD intrinsics are currently not wrapped in VectorEyes.
As always, only a Sith deals in absolutes. The Rust compiler can, in some cases, employ autovectorization to compile code which doesn’t use SIMD operations into code which uses SIMD instructions. Unfortunately, the compiler can’t always autovectorize the way we want it to, which is why VectorEyes exists! ↩
Modules§
- array_
utils - Perform manually unrolled operations on arrays.
Structs§
- Aes128
- A key-scheduled Aes128 block cipher which can both encrypt and decrypt blocks.
- Aes256
- A key-scheduled Aes256 block cipher which can both encrypt and decrypt blocks.
- Aes128
Encrypt Only - A key-scheduled Aes128 block cipher which can only encrypt blocks.
- Aes256
Encrypt Only - A key-scheduled Aes256 block cipher which can only encrypt blocks.
- I8x16
[i8; 16]as a vector.- I8x32
[i8; 32]as a vector.- I16x8
[i16; 8]as a vector.- I16x16
[i16; 16]as a vector.- I32x4
[i32; 4]as a vector.- I32x8
[i32; 8]as a vector.- I64x2
[i64; 2]as a vector.- I64x4
[i64; 4]as a vector.- U8x16
[u8; 16]as a vector.- U8x32
[u8; 32]as a vector.- U16x8
[u16; 8]as a vector.- U16x16
[u16; 16]as a vector.- U32x4
[u32; 4]as a vector.- U32x8
[u32; 8]as a vector.- U64x2
[u64; 2]as a vector.- U64x4
[u64; 4]as a vector.
Enums§
- Vector
Backend - What backend will be used when targeting the current CPU?
Constants§
- VECTOR_
BACKEND - The vector backend that this process is using.
Traits§
- AesBlock
Cipher - An AES block cipher, suitable for encryption.
- AesBlock
Cipher Decrypt - An AES block cipher, suitable for encryption and decryption.
- Extending
Cast - Lossily cast a vector by {zero,sign}-extending its values.
- HasVector
- A
Scalartype which has a vector type of lengthN. - Scalar
- A scalar that can live in the lane of a vector.
- Simd
Base - A vector equivalent to
[T; Self::Lanes]. - Simd
Base8 - A vector containing 8-bit values.
- Simd
Base4x - A vector containing 4 lanes.
- Simd
Base4x64 - A vector containing 4 64-bit values.
- Simd
Base8x - A vector containing 8 lanes.
- Simd
Base16 - A vector containing 16-bit values.
- Simd
Base32 - A vector containing 32-bit values.
- Simd
Base64 - A vector containing 64-bit values.
- Simd
Base Gatherable - A vector supporting the gather operation (indexing into an array using indices from a vector).
- Simd
Saturating Arithmetic - A vector supporting saturating arithmetic on each entry.
Functions§
- assert_
cpu_ features - Panic if the current binary uses features unsupported by the current CPU.
Type Aliases§
- Simd
- An alternative way of naming SIMD types.