Skip to content

Layout of arrays #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion reference/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
85 changes: 85 additions & 0 deletions reference/src/layout/arrays-and-slices.md
Original file line number Diff line number Diff line change
@@ -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::<T>() * 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)
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
# 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"
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)]
Expand Down Expand Up @@ -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 {
Expand Down