Skip to content

Commit

Permalink
flambda-backend: Document arrays of unboxed numbers (#2672)
Browse files Browse the repository at this point in the history
* Document arrays of unboxed numbers:

* Maybe fix markdown

* Notes from review

* Fix HTML anchors

* Try again to fix HTML anchor
  • Loading branch information
ncik-roberts authored Jun 11, 2024
1 parent ba2d0d7 commit 1e7c4d5
Showing 1 changed file with 61 additions and 2 deletions.
63 changes: 61 additions & 2 deletions jane/doc/extensions/unboxed-types/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,17 @@ Here by defining module type `S` with layout `any` and using `with` constraints,
reason about modules with similar shapes but that operate on different layouts. This removes code
duplication and can aid ppxs in supporting unboxed types.

<!-- This heading is referred to by name in a link to an HTML anchor below.
If you rename it, please also update that link.
-->
# `[@layout_poly]` attribute

The attribute enables support for **limited layout polymorphism on external
`%`-primitives**. This is possible because these primitives are always inlined at every
use site. We can thus specialize the function implementation based on the layout
information at each site.

With a `[@layout-poly]` external declaration like this:
With a `[@layout_poly]` external declaration like this:

```ocaml
external[@layout_poly] opaque_identity : ('a : any). 'a -> 'a = "%opaque"
Expand Down Expand Up @@ -270,7 +273,7 @@ let f2 : float# -> float# = magic;; (* ok *)
let f3 : float# -> int32# = magic;; (* error *)
```

This feature is conceptually similar to `[@local_opt]` for modes and would be useful for
This feature is conceptually similar to `[@local_opt]` for modes and is useful for
array access primitives.

Here's the list of primitives that currently support `[@layout_poly]`:
Expand All @@ -285,17 +288,73 @@ Here's the list of primitives that currently support `[@layout_poly]`:
* `%array_safe_set`
* `%array_unsafe_get`
* `%array_unsafe_set`
* `%array_size`

# Arrays of unboxed elements

Arrays can store elements of any layout. You can think of `array` as having been declared as:

```ocaml
type ('a : any) array = (* ... *)
```

Array elements are packed according to their width. For example, arrays of
elements whose layout is `bits32` store two elements per word.

You can use normal array syntax for constructing such an array:

```ocaml
let array = [| #2l |]
```

Array primitives must be declared with `[@layout_poly]` to be usable with arrays of unboxed elements.

```ocaml
module Array = struct
external[@layout_poly] get : ('a : any). 'a array -> int -> 'a = "%array_safe_get"
end
let first_elem () = array.(0)
```

(The above relies on the fact that array projection syntax desugars to a call to whatever `Array.get` is in scope.)

A limited set of primitives may be bound as `[@layout_poly]`;
[see the earlier section](#layout_poly-attribute) for more information.

## Runtime representation

| Array | Tag | Layout of data |
|----------------------------------|--------------------|-------------------------------------------------------------|
| `float# array` | `Double_array_tag` | 64 bits per element |
| `int64# array` | `Custom_tag` | reserved custom block word, followed by 64 bits per element |
| `float32# array`, `int32# array` | `Custom_tag` | reserved custom block word, followed by 32 bits per element |

The above table is written about concrete types like `float#` and `int64#`, but
actually holds for all types of the relevant layout.

The reserved custom block word is the standard custom block field that stores a
pointer to the record of custom operations, like polymorphic equality and
comparison. For unboxed 32-bit element types, like `int32#` and `float32#`, the
custom operations pointer is different for odd-length arrays and even-length
arrays.

Odd-length arrays of 32-bit element type have 32 bits of padding at the end.
The contents of this padding is unspecified, and it is not guaranteed that
the padding value will be preserved by the generated code or the runtime.

# Using unboxed types in structures

Unboxed types can usually be put in structures, though there are some restrictions.

These structures may contain unboxed types, but have some restrictions on field
orders:

* Records
* Constructors

Unboxed numbers can't be put in these structures:

* Constructors with inline record fields
* Exceptions
* Extensible variant constructors
Expand Down

0 comments on commit 1e7c4d5

Please sign in to comment.