From 6358eefb9f8b63f7f7e227cb011ddc4d6b42789e Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 12:06:42 +0100 Subject: [PATCH 01/23] Layout of arrays Closes #91 . --- reference/src/SUMMARY.md | 1 + reference/src/layout/arrays.md | 33 +++++++++++++++++++++++++++++++++ reference/src/layout/vectors.md | 3 ++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 reference/src/layout/arrays.md diff --git a/reference/src/SUMMARY.md b/reference/src/SUMMARY.md index f016c8ba..8d2ea345 100644 --- a/reference/src/SUMMARY.md +++ b/reference/src/SUMMARY.md @@ -18,6 +18,7 @@ - [Integers and Floating Points](./layout/integers-floatingpoint.md) - [Enums](./layout/enums.md) - [Unions](./layout/unions.md) + - [Arrays](./layout/arrays.md) - [Vectors](./layout/vectors.md) - [Optimizations](./optimizations.md) - [Optimizing immutable memory](./optimizations/immutable_memory.md) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md new file mode 100644 index 00000000..226200c8 --- /dev/null +++ b/reference/src/layout/arrays.md @@ -0,0 +1,33 @@ +# Layout of Rust array types + +Array types, `[T; N]`, store `N` values of type `T` contiguously with a constant +_stride_ (the distance between each two consecutive values). + +The offset of the first array element is `0`. + +The stride of the array is computed as the size of the element type rounded up +to the next multiple of the alignment of the element type. That is, the _stride_ +of an array can be larger than the element size iff the alignment requirements +of the element are larger than its size. + +Having a stride larger than the element size allows: + +```rust,ignore +struct A(u16, u8); // size_of == 3, align_of == 4 +type B = [A; 4]; // => stride == 4 > 3 +``` + +The size and alignment of `Vector` element types match, such that `Vector` types +and arrays are layout compatible. + +`repr(C)` arrays have the same layout as C arrays and are passed by pointer in C +FFI according to the C ABI. + +## Unresolved questions + +### Stride > size + +The current layout guarantees for `repr(Rust)` structs guarantee that Rust is forward-compatible with proposals allowing `stride > size`, like: + + * [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/vectors.md index 07bbe94b..53c8cd2a 100644 --- a/reference/src/layout/vectors.md +++ b/reference/src/layout/vectors.md @@ -15,7 +15,8 @@ currently different for each architecture. ## Vector types Vector types are `repr(simd)` homogeneous tuple-structs containing `N` elements -of type `T` where `N` is a power-of-two: +of type `T` where `N` is a power-of-two and the size and alignment requirements +of `T` are equal: ```rust #[repr(simd)] From 3a7fed078dce1504eba0d4ab72ceb76260723048 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:04:58 +0100 Subject: [PATCH 02/23] Document that in current Rust stride == size --- reference/src/layout/arrays.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 226200c8..eddd9400 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -27,7 +27,9 @@ FFI according to the C ABI. ### Stride > size -The current layout guarantees for `repr(Rust)` structs guarantee that Rust is forward-compatible with proposals allowing `stride > size`, like: +In the current Rust implementation, `size >= align` and hence `stride == size` +always holds. However, `stride == size` is not guaranteed here to be +forward-compatible with proposals allowing `stride > size`, like: * [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) From afc53ad384d76fde721d77bef33d56279b2d5e8b Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:14:08 +0100 Subject: [PATCH 03/23] Hyperlink Vector --- reference/src/layout/arrays.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index eddd9400..aaa5deca 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -17,12 +17,14 @@ struct A(u16, u8); // size_of == 3, align_of == 4 type B = [A; 4]; // => stride == 4 > 3 ``` -The size and alignment of `Vector` element types match, such that `Vector` types +The size and alignment of [`Vector`] element types match, such that [`Vector`] types and arrays are layout compatible. `repr(C)` arrays have the same layout as C arrays and are passed by pointer in C FFI according to the C ABI. +[`Vector`]: ./vectors.md + ## Unresolved questions ### Stride > size From 56e7f288d095387a9c8ab565e7a0a8316a9d7d4f Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:15:45 +0100 Subject: [PATCH 04/23] There are no repr(C) arrays --- reference/src/layout/arrays.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index aaa5deca..baf5d217 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -20,9 +20,6 @@ type B = [A; 4]; // => stride == 4 > 3 The size and alignment of [`Vector`] element types match, such that [`Vector`] types and arrays are layout compatible. -`repr(C)` arrays have the same layout as C arrays and are passed by pointer in C -FFI according to the C ABI. - [`Vector`]: ./vectors.md ## Unresolved questions From b8e108bd56c1f847b3952c984d6abc3f4befeb82 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:19:52 +0100 Subject: [PATCH 05/23] Further clarify Vector layout --- reference/src/layout/arrays.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index baf5d217..3948a1e7 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -17,10 +17,12 @@ struct A(u16, u8); // size_of == 3, align_of == 4 type B = [A; 4]; // => stride == 4 > 3 ``` -The size and alignment of [`Vector`] element types match, such that [`Vector`] types -and arrays are layout compatible. +The size and alignment of the element types supported by the [Vector] layout +[^1] match. Therefore, types with [Vector] layout are layout compatible with +arrays of the same element type and number of elements. -[`Vector`]: ./vectors.md +[^1]: The Vector layout is the layout of `repr(simd)` types like `__m128`. +[Vector]: ./vectors.md ## Unresolved questions From 324e98d37e4c6d47c3c9e5b29b6dc9b2768eb333 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:21:57 +0100 Subject: [PATCH 06/23] Expand definition of stride --- reference/src/layout/arrays.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 3948a1e7..170633fe 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -1,7 +1,8 @@ # Layout of Rust array types Array types, `[T; N]`, store `N` values of type `T` contiguously with a constant -_stride_ (the distance between each two consecutive values). +_stride_, where _stride_ is the distance between each pair of consecutive values +within the array. The offset of the first array element is `0`. From 6e1036ba50a725b433a5e72c1bd5e6de0b80cfa7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:23:19 +0100 Subject: [PATCH 07/23] Expand consequence of offset 0 --- reference/src/layout/arrays.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 170633fe..618bd7c6 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -4,7 +4,8 @@ Array types, `[T; N]`, store `N` values of type `T` contiguously with a constant _stride_, where _stride_ is the distance between each pair of consecutive values within the array. -The offset of the first array element is `0`. +The offset of the first array element is `0`, that is, a pointer to the array +and a pointer to its first element have the same address. The stride of the array is computed as the size of the element type rounded up to the next multiple of the alignment of the element type. That is, the _stride_ From 43a21a41486decbc6038172725018facbe329290 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:42:12 +0100 Subject: [PATCH 08/23] Reword the proposal --- reference/src/layout/arrays.md | 52 +++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 618bd7c6..2342d57e 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -1,38 +1,52 @@ # Layout of Rust array types -Array types, `[T; N]`, store `N` values of type `T` contiguously with a constant +Array types, `[T; N]`, store `N` values of type `T` with a constant _stride_, where _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 +The _offset_ of the first array element is `0`, that is, a pointer to the array and a pointer to its first element have the same address. -The stride of the array is computed as the size of the element type rounded up -to the next multiple of the alignment of the element type. That is, the _stride_ -of an array can be larger than the element size iff the alignment requirements -of the element are larger than its size. +The _stride_ of the array is computed as the _size_ of the element type rounded up +to the next multiple of the _alignment_ of the element type. -Having a stride larger than the element size allows: +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`[^1]. -```rust,ignore -struct A(u16, u8); // size_of == 3, align_of == 4 -type B = [A; 4]; // => stride == 4 > 3 -``` +[^1]: The alignment of the array is, however, unspecified. -The size and alignment of the element types supported by the [Vector] layout -[^1] match. Therefore, types with [Vector] layout are layout compatible with -arrays of the same element type and number of elements. +The [layout of Vector types] [^2] requires the size and alignment of the Vector +elements to match. That is, types with Vector layout are layout compatible with +arrays having the same element type and number of elements as the Vector. -[^1]: The Vector layout is the layout of `repr(simd)` types like `__m128`. +[^2]: The Vector layout is the layout of `repr(simd)` types like `__m128`. [Vector]: ./vectors.md ## Unresolved questions -### Stride > size +### Guaranteeing `stride == size` ? + +The element _size_ is not guaranteed to be a multiple of the element's +alignment. In: + +```rust,ignore +struct A(u16, u8); +type B = [A; 4]; +``` + +and in the current Rust implementation, `A` has an alignment and a size of `4`, +and `B` has a size of `16`. However, the size of `A` is not guaranteed by the +[layout of structs and tuples]. + +[layout of structs and tuples]: ./structs-and-tuples.md + +If a future Rust implementation wanted to use a smaller size for `A`, that is, a +`size == 3`, then `B` would need a `stride == 4` to ensure that its elements are +properly aligned, resulting in a `stride > size`. -In the current Rust implementation, `size >= align` and hence `stride == size` -always holds. However, `stride == size` is not guaranteed here to be -forward-compatible with proposals allowing `stride > size`, like: +The current guarantee that `stride >= size` is forward-compatible with the open +proposals about allowing `A` to have a size of `3`: * [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) From 8c0d1ffc7133f13a9c5d12021e052004dcccf87c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:50:30 +0100 Subject: [PATCH 09/23] More rewording --- reference/src/layout/arrays.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 2342d57e..d7f3e3f7 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -14,9 +14,14 @@ 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`[^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]: The alignment of the array is, however, unspecified. +[layout of structs and tuples]: ./structs-and-tuples.md -The [layout of Vector types] [^2] requires the size and alignment of the Vector +The [layout of Vector types] [^2] requires the _size_ and _alignment_ of the Vector elements to match. That is, types with Vector layout are layout compatible with arrays having the same element type and number of elements as the Vector. @@ -27,26 +32,25 @@ arrays having the same element type and number of elements as the Vector. ### Guaranteeing `stride == size` ? -The element _size_ is not guaranteed to be a multiple of the element's -alignment. In: +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]; ``` -and in the current Rust implementation, `A` has an alignment and a size of `4`, -and `B` has a size of `16`. However, the size of `A` is not guaranteed by the -[layout of structs and tuples]. - -[layout of structs and tuples]: ./structs-and-tuples.md +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. -If a future Rust implementation wanted to use a smaller size for `A`, that is, a -`size == 3`, then `B` would need a `stride == 4` to ensure that its elements are -properly aligned, resulting in a `stride > size`. +However, a future Rust implementation could, as a layout optimization, choose a +smaller size for `A` (that is, `3`). For `A` elements to be properly aligned +within `B`, then `B` would need to choose a `stride == 4`, resulting in a +`stride > size`. -The current guarantee that `stride >= size` is forward-compatible with the open -proposals about allowing `A` to have a size of `3`: +Guaranteeing `stride >= size` is forward-compatible such the 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) From d5221e7e68022d3e5f6419aea1df7d76ecd06b2b Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:53:16 +0100 Subject: [PATCH 10/23] Clarify why the array alignment is unspecified --- reference/src/layout/arrays.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index d7f3e3f7..dd1a5d5f 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -5,7 +5,7 @@ _stride_, where _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 have the same address. +and a pointer to its first element point to the same memory address. The _stride_ of the array is computed as the _size_ of the element type rounded up to the next multiple of the _alignment_ of the element type. @@ -18,8 +18,12 @@ In this case, the size of the array can be computed as `size_of::() * N`[^1]. > the element's _alignment_, and therefore `stride == size` always holds. This > is, however, not guaranteed by the [layout of structs and tuples]. -[^1]: The alignment of the array is, however, unspecified. +[^1]: The alignment of the array is, however, unspecified. For example, the +[SysV AMD64 ABI] requires array arguments to be at least 16 byte aligned to +allow the use of SSE instructions. + [layout of structs and tuples]: ./structs-and-tuples.md +[SysV AMD64 ABI]: https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf The [layout of Vector types] [^2] requires the _size_ and _alignment_ of the Vector elements to match. That is, types with Vector layout are layout compatible with From 0f358b2f46c4fbebd1565d15bcb37e65767155ce Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:54:23 +0100 Subject: [PATCH 11/23] Fix Vector links --- reference/src/layout/arrays.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index dd1a5d5f..1faac231 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -25,11 +25,11 @@ allow the use of SSE instructions. [layout of structs and tuples]: ./structs-and-tuples.md [SysV AMD64 ABI]: https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf -The [layout of Vector types] [^2] requires the _size_ and _alignment_ of the Vector -elements to match. That is, types with Vector layout are layout compatible with +The [layout of Vector types][Vector] [^2] requires the _size_ and _alignment_ of the [Vector] +elements to match. That is, types with [Vector] layout are layout compatible with arrays having the same element type and number of elements as the Vector. -[^2]: The Vector layout is the layout of `repr(simd)` types like `__m128`. +[^2]: The [Vector] layout is the layout of `repr(simd)` types like `__m128`. [Vector]: ./vectors.md ## Unresolved questions From 70ed080f091bffe398320dc64c6d7a4db83bacfe Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 17:54:59 +0100 Subject: [PATCH 12/23] Language --- reference/src/layout/arrays.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 1faac231..cbc53b1a 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -25,9 +25,10 @@ allow the use of SSE instructions. [layout of structs and tuples]: ./structs-and-tuples.md [SysV AMD64 ABI]: https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf -The [layout of Vector types][Vector] [^2] requires the _size_ and _alignment_ of the [Vector] -elements to match. That is, types with [Vector] layout are layout compatible with -arrays having the same element type and number of elements as the Vector. +The [layout of Vector types][Vector] [^2] requires the _size_ and _alignment_ of +the [Vector] elements to match. That is, types with [Vector] layout are layout +compatible with arrays having the same element type and the same number of +elements as the Vector. [^2]: The [Vector] layout is the layout of `repr(simd)` types like `__m128`. [Vector]: ./vectors.md From 0f8a4f59c33717e17c1501b6b3624c7a315392a0 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 18:10:11 +0100 Subject: [PATCH 13/23] Fix rendering --- reference/src/layout/arrays.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index cbc53b1a..ece8a798 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -1,18 +1,20 @@ # Layout of Rust array types -Array types, `[T; N]`, store `N` values of type `T` with a constant -_stride_, where _stride_ is the distance between each pair of consecutive values -within the array. +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 point to the same memory address. +and a pointer to its first element both point to the same memory address. The _stride_ of the array is computed as the _size_ of the element type rounded up to the next multiple of the _alignment_ of the element type. 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`[^1]. +In this case, the _size_ of the array can be computed as `size_of::() * N`[^1], +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`[^2]. > **Note:** In the current Rust implementation, _size_ is always a multiple of > the element's _alignment_, and therefore `stride == size` always holds. This @@ -22,16 +24,21 @@ In this case, the size of the array can be computed as `size_of::() * N`[^1]. [SysV AMD64 ABI] requires array arguments to be at least 16 byte aligned to allow the use of SSE instructions. +[^2]: 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 [SysV AMD64 ABI]: https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf -The [layout of Vector types][Vector] [^2] requires the _size_ and _alignment_ of +The [layout of Vector types][Vector] [^3] requires the _size_ and _alignment_ of the [Vector] elements to match. That is, types with [Vector] layout are layout compatible with arrays having the same element type and the same number of -elements as the Vector. +elements as the [Vector]. + +[^3]: The [Vector] layout is the layout of `repr(simd)` types like [`__m128`]. -[^2]: The [Vector] layout is the layout of `repr(simd)` types like `__m128`. -[Vector]: ./vectors.md +[Vector]: vectors.md +[`__m128`]: https://doc.rust-lang.org/core/arch/x86_64/struct.__m128.html ## Unresolved questions @@ -49,10 +56,9 @@ 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, as a layout optimization, choose a -smaller size for `A` (that is, `3`). For `A` elements to be properly aligned -within `B`, then `B` would need to choose a `stride == 4`, resulting in a -`stride > size`. +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 such the layout-optimization proposals: From 7511825536ffe3dcd7c3643262e5471795f228b7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 18:32:37 +0100 Subject: [PATCH 14/23] Guarantees about array alignment --- reference/src/layout/arrays.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index ece8a798..8e34843d 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -7,35 +7,34 @@ 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. + The _stride_ of the array is computed as the _size_ of the element type rounded up to the next multiple of the _alignment_ of the element type. 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`[^1], +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`[^2]. +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]: The alignment of the array is, however, unspecified. For example, the -[SysV AMD64 ABI] requires array arguments to be at least 16 byte aligned to -allow the use of SSE instructions. - -[^2]: When `stride > size` the pointer needs to be advanced by the array +[^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 -[SysV AMD64 ABI]: https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf -The [layout of Vector types][Vector] [^3] requires the _size_ and _alignment_ of +The [layout of Vector types][Vector] [^2] requires the _size_ and _alignment_ of the [Vector] elements to match. That is, types with [Vector] layout are layout compatible with arrays having the same element type and the same number of elements as the [Vector]. -[^3]: The [Vector] layout is the layout of `repr(simd)` types like [`__m128`]. +[^2]: The [Vector] layout is the layout of `repr(simd)` types like [`__m128`]. [Vector]: vectors.md [`__m128`]: https://doc.rust-lang.org/core/arch/x86_64/struct.__m128.html From e3df96cd57a323d217000cf2deedbae701ecc24c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 18:41:18 +0100 Subject: [PATCH 15/23] Document array types in C FFI --- reference/src/layout/arrays.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 8e34843d..ec1e0bdc 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -11,8 +11,17 @@ 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. -The _stride_ of the array is computed as the _size_ of the element type rounded up -to the next multiple of the _alignment_ of the 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 an +> array as an argument, but a pointer to the element type 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]; }`. + +The _stride_ of the array is the distance between a pair of consecutive values +within the array, and it is constant for all element pairs. It is computed as +the _size_ of the element type rounded up to the next multiple of the +_alignment_ of the element type. 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]`. From 472f2262e6ef58431414b223b717d10a81758c10 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 18:43:36 +0100 Subject: [PATCH 16/23] Language --- reference/src/layout/arrays.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index ec1e0bdc..26009436 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -12,11 +12,12 @@ 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 an -> array as an argument, but a pointer to the element type 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]; }`. +> 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]; }`. The _stride_ of the array is the distance between a pair of consecutive values within the array, and it is constant for all element pairs. It is computed as From 9b45f312e10c760c82cc4086dd73d9152b648b7a Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 6 Mar 2019 18:51:34 +0100 Subject: [PATCH 17/23] Language --- reference/src/layout/arrays.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/src/layout/arrays.md b/reference/src/layout/arrays.md index 26009436..70d81192 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays.md @@ -69,8 +69,8 @@ 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 such the layout-optimization -proposals: +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) From 40e88dd9fce45fa2153a7e2222d73e60108997d9 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 7 Mar 2019 09:38:37 +0100 Subject: [PATCH 18/23] Add layout of slices; clarify packed SIMD vectors --- reference/src/SUMMARY.md | 4 ++-- .../{arrays.md => arrays-and-slices.md} | 22 ++++++++++++++----- .../{vectors.md => packed-simd-vectors.md} | 18 +++++++-------- 3 files changed, 27 insertions(+), 17 deletions(-) rename reference/src/layout/{arrays.md => arrays-and-slices.md} (84%) rename reference/src/layout/{vectors.md => packed-simd-vectors.md} (80%) diff --git a/reference/src/SUMMARY.md b/reference/src/SUMMARY.md index 8d2ea345..4079c2bc 100644 --- a/reference/src/SUMMARY.md +++ b/reference/src/SUMMARY.md @@ -18,8 +18,8 @@ - [Integers and Floating Points](./layout/integers-floatingpoint.md) - [Enums](./layout/enums.md) - [Unions](./layout/unions.md) - - [Arrays](./layout/arrays.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.md b/reference/src/layout/arrays-and-slices.md similarity index 84% rename from reference/src/layout/arrays.md rename to reference/src/layout/arrays-and-slices.md index 70d81192..f12c5e63 100644 --- a/reference/src/layout/arrays.md +++ b/reference/src/layout/arrays-and-slices.md @@ -1,4 +1,6 @@ -# Layout of Rust array types +# 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 @@ -24,6 +26,8 @@ within the array, and it is constant for all element pairs. 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`, @@ -39,16 +43,22 @@ pointer to the first element of the array by `i`[^1]. [layout of structs and tuples]: ./structs-and-tuples.md -The [layout of Vector types][Vector] [^2] requires the _size_ and _alignment_ of -the [Vector] elements to match. That is, types with [Vector] layout are layout -compatible with arrays having the same element type and the same number of -elements as the [Vector]. +### 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] layout are layout compatible with arrays having the same element type +and the same number of elements as the [vector]. [^2]: The [Vector] layout is the layout of `repr(simd)` types like [`__m128`]. -[Vector]: vectors.md +[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` ? diff --git a/reference/src/layout/vectors.md b/reference/src/layout/packed-simd-vectors.md similarity index 80% rename from reference/src/layout/vectors.md rename to reference/src/layout/packed-simd-vectors.md index 53c8cd2a..18d21b5d 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,17 +6,17 @@ 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 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 +## Packed SIMD vector types -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: +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)] From 516847e8cf37b3333fc9103e357dfdafa7c744b7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 7 Mar 2019 09:44:16 +0100 Subject: [PATCH 19/23] Fix links --- reference/src/layout/arrays-and-slices.md | 8 ++++---- reference/src/layout/packed-simd-vectors.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/reference/src/layout/arrays-and-slices.md b/reference/src/layout/arrays-and-slices.md index f12c5e63..ae53795f 100644 --- a/reference/src/layout/arrays-and-slices.md +++ b/reference/src/layout/arrays-and-slices.md @@ -46,11 +46,11 @@ pointer to the first element of the array by `i`[^1]. ### 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] layout are layout compatible with arrays having the same element type -and the same number of elements as the [vector]. +_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 [Vector] layout is the layout of `repr(simd)` types like [`__m128`]. +[^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 diff --git a/reference/src/layout/packed-simd-vectors.md b/reference/src/layout/packed-simd-vectors.md index 18d21b5d..5c8b9604 100644 --- a/reference/src/layout/packed-simd-vectors.md +++ b/reference/src/layout/packed-simd-vectors.md @@ -60,8 +60,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 { From 64f6ea602c0f1134153de374048be50336b7ff9e Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 7 Mar 2019 09:53:58 +0100 Subject: [PATCH 20/23] Add footnote clarifying what packed means --- reference/src/layout/packed-simd-vectors.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/packed-simd-vectors.md b/reference/src/layout/packed-simd-vectors.md index 5c8b9604..12bdf891 100644 --- a/reference/src/layout/packed-simd-vectors.md +++ b/reference/src/layout/packed-simd-vectors.md @@ -6,12 +6,16 @@ not to change until an RFC ratifies them. [#38]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/38 -Rust currently exposes packed SIMD vector types like `__m128` to users, but it +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 packed SIMD vector types is _implementation-defined_ and it is currently different for each architecture. +[^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. + ## Packed SIMD vector types Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs containing From e9835921b4e10d1af0ca0d2806574d1f2f6cb02e Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 7 Mar 2019 09:56:38 +0100 Subject: [PATCH 21/23] Add link to RFC2366 text --- reference/src/layout/packed-simd-vectors.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/packed-simd-vectors.md b/reference/src/layout/packed-simd-vectors.md index 12bdf891..fa3f879b 100644 --- a/reference/src/layout/packed-simd-vectors.md +++ b/reference/src/layout/packed-simd-vectors.md @@ -14,7 +14,10 @@ _implementation-defined_ and it is currently different for each architecture. [^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. + 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 ## Packed SIMD vector types From 292039e2da0cd9ac8f481e045c90215f48376bc2 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 7 Mar 2019 11:27:53 +0100 Subject: [PATCH 22/23] Structs and unions containing array are fine in C FFI --- reference/src/layout/arrays-and-slices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/layout/arrays-and-slices.md b/reference/src/layout/arrays-and-slices.md index ae53795f..a345565f 100644 --- a/reference/src/layout/arrays-and-slices.md +++ b/reference/src/layout/arrays-and-slices.md @@ -19,7 +19,7 @@ guaranteed to be the same as the layout of a C array with the same element type. > 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]; }`. +> [U; M]; }`, and `struct`s and `union`s containing arrays are also fine. The _stride_ of the array is the distance between a pair of consecutive values within the array, and it is constant for all element pairs. It is computed as From 9ffe8067833eafad62f7755dfb81987f961d77f9 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 7 Mar 2019 11:28:45 +0100 Subject: [PATCH 23/23] Avoid repetition --- reference/src/layout/arrays-and-slices.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/reference/src/layout/arrays-and-slices.md b/reference/src/layout/arrays-and-slices.md index a345565f..375d1571 100644 --- a/reference/src/layout/arrays-and-slices.md +++ b/reference/src/layout/arrays-and-slices.md @@ -21,9 +21,8 @@ guaranteed to be the same as the layout of a C array with the same element type. > }`. 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 the distance between a pair of consecutive values -within the array, and it is constant for all element pairs. It is computed as -the _size_ of the element type rounded up to the next multiple of the +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`