diff --git a/reference/src/SUMMARY.md b/reference/src/SUMMARY.md index f016c8ba..4079c2bc 100644 --- a/reference/src/SUMMARY.md +++ b/reference/src/SUMMARY.md @@ -18,7 +18,8 @@ - [Integers and Floating Points](./layout/integers-floatingpoint.md) - [Enums](./layout/enums.md) - [Unions](./layout/unions.md) - - [Vectors](./layout/vectors.md) + - [Arrays and Slices](./layout/arrays-and-slices.md) + - [Packed SIMD vectors](./layout/packed-simd-vectors.md) - [Optimizations](./optimizations.md) - [Optimizing immutable memory](./optimizations/immutable_memory.md) - [Glossary](./glossary.md) diff --git a/reference/src/layout/arrays-and-slices.md b/reference/src/layout/arrays-and-slices.md new file mode 100644 index 00000000..375d1571 --- /dev/null +++ b/reference/src/layout/arrays-and-slices.md @@ -0,0 +1,85 @@ +# Layout of Rust array types and slices + +## Layout of Rust array types + +Array types, `[T; N]`, store `N` values of type `T` with a constant _stride_. +Here, _stride_ is the distance between each pair of consecutive values within +the array. + +The _offset_ of the first array element is `0`, that is, a pointer to the array +and a pointer to its first element both point to the same memory address. + +The _alignment_ of array types is greater or equal to the alignment of its +element type. If the element type is `repr(C)` the layout of the array is +guaranteed to be the same as the layout of a C array with the same element type. + +> **Note**: the type of array arguments in C function signatures, e.g., `void +> foo(T x[N])`, decays to a pointer. That is, these functions do not take arrays +> as an arguments, they take a pointer to the first element of the array +> instead. Array types are therefore _improper C types_ (not C FFI safe) in Rust +> foreign function declarations, e.g., `extern { fn foo(x: [T; N]) -> [U; M]; +> }`. Pointers to arrays are fine: `extern { fn foo(x: *const [T; N]) -> *const +> [U; M]; }`, and `struct`s and `union`s containing arrays are also fine. + +The _stride_ of the array is constant for all element pairs and it is computed +as the _size_ of the element type rounded up to the next multiple of the +_alignment_ of the element type. + +### Special case `stride == size` + +When the element _size_ is a multiple of the element's _alignment_, then `stride +== size`, and the elements are laid out contiguously in memory, e.g., `[u8; 4]`. +In this case, the _size_ of the array can be computed as `size_of::() * N`, +and a pointer to the `i`-th element of the array can be obtained by offsetting a +pointer to the first element of the array by `i`[^1]. + +> **Note:** In the current Rust implementation, _size_ is always a multiple of +> the element's _alignment_, and therefore `stride == size` always holds. This +> is, however, not guaranteed by the [layout of structs and tuples]. + +[^1]: When `stride > size` the pointer needs to be advanced by the array + _stride_ instead of by the element _size_. + +[layout of structs and tuples]: ./structs-and-tuples.md + +### Layout compatibility with packed SIMD vectors + +The [layout of packed SIMD vector types][Vector] [^2] requires the _size_ and +_alignment_ of the vector elements to match. That is, types with [packed SIMD +vector][Vector] layout are layout compatible with arrays having the same element +type and the same number of elements as the vector. + +[^2]: The [packed SIMD vector][Vector] layout is the layout of `repr(simd)` types like [`__m128`]. + +[Vector]: packed-simd-vectors.md +[`__m128`]: https://doc.rust-lang.org/core/arch/x86_64/struct.__m128.html + +## Layout of Rust slices + +The layout of a slice `[T]` of length `N` is the same as that of a `[T; N]` array. + +## Unresolved questions + +### Guaranteeing `stride == size` ? + +Currently, the [layout of structs and tuples] does not guarantee that the +element _size_ is a multiple of its _alignment_. For example, consider: + +```rust,ignore +struct A(u16, u8); +type B = [A; 4]; +``` + +In the current Rust implementation, `A` has an alignment and a size of `4`, and +`B` has a size of `16`, such that `B` contains four `A`s that are contiguously +laid in memory. + +However, a future Rust implementation could implement a layout optimization that +reduces the size of `A` to `3`. For the elements of `B` to be properly aligned, +`B` would need to choose a `stride == 4`, resulting in a `stride > size`. + +Guaranteeing `stride >= size` is forward-compatible with such +layout-optimization proposals: + + * [rust-lang/rfcs/1397: Spearate size and stride for types](https://github.com/rust-lang/rfcs/issues/1397) + * [rust-lang/rust/17027: Collapse trailing padding](https://github.com/rust-lang/rust/issues/17027) diff --git a/reference/src/layout/vectors.md b/reference/src/layout/packed-simd-vectors.md similarity index 67% rename from reference/src/layout/vectors.md rename to reference/src/layout/packed-simd-vectors.md index 07bbe94b..fa3f879b 100644 --- a/reference/src/layout/vectors.md +++ b/reference/src/layout/packed-simd-vectors.md @@ -1,4 +1,4 @@ -# Layout of vectors +# Layout of packed SIMD vectors **Disclaimer:** This chapter represents the consensus from issue [#38]. The statements in here are not (yet) "guaranteed" @@ -6,16 +6,24 @@ not to change until an RFC ratifies them. [#38]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/38 -Rust currently exposes vector types like `__m128` to users, but it does not -expose a way for users to construct their own vector types. +Rust currently exposes packed[^1] SIMD vector types like `__m128` to users, but it +does not expose a way for users to construct their own vector types. -The set of currently-exposed vector types is _implementation-defined_ and it is -currently different for each architecture. +The set of currently-exposed packed SIMD vector types is +_implementation-defined_ and it is currently different for each architecture. -## Vector types +[^1]: _packed_ denotes that these SIMD vectors have a compile-time fixed size, + distinguishing these from SIMD vector types whose size is only known at + run-time. Rust currently only supports _packed_ SIMD vector types. This is + elaborated further in [RFC2366]. + +[RFC2366]: https://github.com/gnzlbg/rfcs/blob/ppv/text/0000-ppv.md#interaction-with-cray-vectors -Vector types are `repr(simd)` homogeneous tuple-structs containing `N` elements -of type `T` where `N` is a power-of-two: +## Packed SIMD vector types + +Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs containing +`N` elements of type `T` where `N` is a power-of-two and the size and alignment +requirements of `T` are equal: ```rust #[repr(simd)] @@ -59,8 +67,8 @@ unsafe { ### Unresolved questions -* **Blocked**: Should the layout of vectors be the same as that of homogeneous - tuples ? Such that: +* **Blocked**: Should the layout of packed SIMD vectors be the same as that of + homogeneous tuples ? Such that: ```rust union U {