Skip to content

Commit c4c1859

Browse files
authored
Layout of arrays (#94)
Closes #91 .
1 parent c3e2ef7 commit c4c1859

File tree

3 files changed

+105
-11
lines changed

3 files changed

+105
-11
lines changed

reference/src/SUMMARY.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
- [Integers and Floating Points](./layout/integers-floatingpoint.md)
1919
- [Enums](./layout/enums.md)
2020
- [Unions](./layout/unions.md)
21-
- [Vectors](./layout/vectors.md)
21+
- [Arrays and Slices](./layout/arrays-and-slices.md)
22+
- [Packed SIMD vectors](./layout/packed-simd-vectors.md)
2223
- [Optimizations](./optimizations.md)
2324
- [Optimizing immutable memory](./optimizations/immutable_memory.md)
2425
- [Glossary](./glossary.md)
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Layout of Rust array types and slices
2+
3+
## Layout of Rust array types
4+
5+
Array types, `[T; N]`, store `N` values of type `T` with a constant _stride_.
6+
Here, _stride_ is the distance between each pair of consecutive values within
7+
the array.
8+
9+
The _offset_ of the first array element is `0`, that is, a pointer to the array
10+
and a pointer to its first element both point to the same memory address.
11+
12+
The _alignment_ of array types is greater or equal to the alignment of its
13+
element type. If the element type is `repr(C)` the layout of the array is
14+
guaranteed to be the same as the layout of a C array with the same element type.
15+
16+
> **Note**: the type of array arguments in C function signatures, e.g., `void
17+
> foo(T x[N])`, decays to a pointer. That is, these functions do not take arrays
18+
> as an arguments, they take a pointer to the first element of the array
19+
> instead. Array types are therefore _improper C types_ (not C FFI safe) in Rust
20+
> foreign function declarations, e.g., `extern { fn foo(x: [T; N]) -> [U; M];
21+
> }`. Pointers to arrays are fine: `extern { fn foo(x: *const [T; N]) -> *const
22+
> [U; M]; }`, and `struct`s and `union`s containing arrays are also fine.
23+
24+
The _stride_ of the array is constant for all element pairs and it is computed
25+
as the _size_ of the element type rounded up to the next multiple of the
26+
_alignment_ of the element type.
27+
28+
### Special case `stride == size`
29+
30+
When the element _size_ is a multiple of the element's _alignment_, then `stride
31+
== size`, and the elements are laid out contiguously in memory, e.g., `[u8; 4]`.
32+
In this case, the _size_ of the array can be computed as `size_of::<T>() * N`,
33+
and a pointer to the `i`-th element of the array can be obtained by offsetting a
34+
pointer to the first element of the array by `i`[^1].
35+
36+
> **Note:** In the current Rust implementation, _size_ is always a multiple of
37+
> the element's _alignment_, and therefore `stride == size` always holds. This
38+
> is, however, not guaranteed by the [layout of structs and tuples].
39+
40+
[^1]: When `stride > size` the pointer needs to be advanced by the array
41+
_stride_ instead of by the element _size_.
42+
43+
[layout of structs and tuples]: ./structs-and-tuples.md
44+
45+
### Layout compatibility with packed SIMD vectors
46+
47+
The [layout of packed SIMD vector types][Vector] [^2] requires the _size_ and
48+
_alignment_ of the vector elements to match. That is, types with [packed SIMD
49+
vector][Vector] layout are layout compatible with arrays having the same element
50+
type and the same number of elements as the vector.
51+
52+
[^2]: The [packed SIMD vector][Vector] layout is the layout of `repr(simd)` types like [`__m128`].
53+
54+
[Vector]: packed-simd-vectors.md
55+
[`__m128`]: https://doc.rust-lang.org/core/arch/x86_64/struct.__m128.html
56+
57+
## Layout of Rust slices
58+
59+
The layout of a slice `[T]` of length `N` is the same as that of a `[T; N]` array.
60+
61+
## Unresolved questions
62+
63+
### Guaranteeing `stride == size` ?
64+
65+
Currently, the [layout of structs and tuples] does not guarantee that the
66+
element _size_ is a multiple of its _alignment_. For example, consider:
67+
68+
```rust,ignore
69+
struct A(u16, u8);
70+
type B = [A; 4];
71+
```
72+
73+
In the current Rust implementation, `A` has an alignment and a size of `4`, and
74+
`B` has a size of `16`, such that `B` contains four `A`s that are contiguously
75+
laid in memory.
76+
77+
However, a future Rust implementation could implement a layout optimization that
78+
reduces the size of `A` to `3`. For the elements of `B` to be properly aligned,
79+
`B` would need to choose a `stride == 4`, resulting in a `stride > size`.
80+
81+
Guaranteeing `stride >= size` is forward-compatible with such
82+
layout-optimization proposals:
83+
84+
* [rust-lang/rfcs/1397: Spearate size and stride for types](https://github.com/rust-lang/rfcs/issues/1397)
85+
* [rust-lang/rust/17027: Collapse trailing padding](https://github.com/rust-lang/rust/issues/17027)

reference/src/layout/vectors.md renamed to reference/src/layout/packed-simd-vectors.md

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
1-
# Layout of vectors
1+
# Layout of packed SIMD vectors
22

33
**Disclaimer:** This chapter represents the consensus from issue
44
[#38]. The statements in here are not (yet) "guaranteed"
55
not to change until an RFC ratifies them.
66

77
[#38]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/38
88

9-
Rust currently exposes vector types like `__m128` to users, but it does not
10-
expose a way for users to construct their own vector types.
9+
Rust currently exposes packed[^1] SIMD vector types like `__m128` to users, but it
10+
does not expose a way for users to construct their own vector types.
1111

12-
The set of currently-exposed vector types is _implementation-defined_ and it is
13-
currently different for each architecture.
12+
The set of currently-exposed packed SIMD vector types is
13+
_implementation-defined_ and it is currently different for each architecture.
1414

15-
## Vector types
15+
[^1]: _packed_ denotes that these SIMD vectors have a compile-time fixed size,
16+
distinguishing these from SIMD vector types whose size is only known at
17+
run-time. Rust currently only supports _packed_ SIMD vector types. This is
18+
elaborated further in [RFC2366].
19+
20+
[RFC2366]: https://github.com/gnzlbg/rfcs/blob/ppv/text/0000-ppv.md#interaction-with-cray-vectors
1621

17-
Vector types are `repr(simd)` homogeneous tuple-structs containing `N` elements
18-
of type `T` where `N` is a power-of-two:
22+
## Packed SIMD vector types
23+
24+
Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs containing
25+
`N` elements of type `T` where `N` is a power-of-two and the size and alignment
26+
requirements of `T` are equal:
1927

2028
```rust
2129
#[repr(simd)]
@@ -59,8 +67,8 @@ unsafe {
5967

6068
### Unresolved questions
6169

62-
* **Blocked**: Should the layout of vectors be the same as that of homogeneous
63-
tuples ? Such that:
70+
* **Blocked**: Should the layout of packed SIMD vectors be the same as that of
71+
homogeneous tuples ? Such that:
6472

6573
```rust
6674
union U {

0 commit comments

Comments
 (0)