Skip to content

Commit

Permalink
Layout of arrays (#94)
Browse files Browse the repository at this point in the history
Closes #91 .
  • Loading branch information
gnzlbg authored Mar 14, 2019
1 parent c3e2ef7 commit c4c1859
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 11 deletions.
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

0 comments on commit c4c1859

Please sign in to comment.