Skip to content

Commit

Permalink
Merge branch 'master' into minor-edits
Browse files Browse the repository at this point in the history
  • Loading branch information
ravicodelabs committed Nov 7, 2023
2 parents 9153f28 + 6af3f81 commit 914a935
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Please see the [CONTRIBUTING.md] file for more details.

## Translations to other languages

* [Bulgarian](https://github.com/kberov/rust-by-example-bg)
* [Chinese](https://github.com/rust-lang-cn/rust-by-example-cn)
* [Japanese](https://github.com/rust-lang-ja/rust-by-example-ja)
* [French](https://github.com/Songbird0/FR_RBE)
Expand Down
10 changes: 5 additions & 5 deletions src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ Now let's begin!

- [Types](types.md) - Learn about changing and defining types.

- [Conversion](conversion.md)
- [Conversion](conversion.md) - Convert between different types, such as strings, integers, and floats.

- [Expressions](expression.md)
- [Expressions](expression.md) - Learn about Expressions & how to use them.

- [Flow of Control](flow_control.md) - `if`/`else`, `for`, and others.

Expand All @@ -43,7 +43,7 @@ Now let's begin!

- [Traits](trait.md) - A trait is a collection of methods defined for an unknown type: `Self`

- [Macros](macros.md)
- [Macros](macros.md) - Macros are a way of writing code that writes other code, which is known as metaprogramming.

- [Error handling](error.md) - Learn Rust way of handling failures.

Expand All @@ -53,9 +53,9 @@ Now let's begin!

- [Testing](testing.md) - All sorts of testing in Rust.

- [Unsafe Operations](unsafe.md)
- [Unsafe Operations](unsafe.md) - Learn about entering a block of unsafe operations.

- [Compatibility](compatibility.md)
- [Compatibility](compatibility.md) - Handling Rust's evolution and potential compatibility issues.

- [Meta](meta.md) - Documentation, Benchmarking.

Expand Down
11 changes: 6 additions & 5 deletions src/unsafe/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ can be written at any time, and can therefore not share its location with any ot
However, to guarantee optimal performance it is important to use as few registers as possible,
so they won't have to be saved and reloaded around the inline assembly block.
To achieve this Rust provides a `lateout` specifier. This can be used on any output that is
written only after all inputs have been consumed.
There is also a `inlateout` variant of this specifier.
written only after all inputs have been consumed. There is also an `inlateout` variant of this
specifier.

Here is an example where `inlateout` *cannot* be used in `release` mode or other optimized cases:

Expand All @@ -163,11 +163,12 @@ unsafe {
assert_eq!(a, 12);
# }
```
The above could work well in unoptimized cases (`Debug` mode), but if you want optimized performance (`release` mode or other optimized cases), it could not work.

That is because in optimized cases, the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction could overwrite the value of `c` and cause the assembly code to produce the wrong result.
In unoptimized cases (e.g. `Debug` mode), replacing `inout(reg) a` with `inlateout(reg) a` in the above example can continue to give the expected result. However, with `release` mode or other optimized cases, using `inlateout(reg) a` can instead lead to the final value `a = 16`, causing the assertion to fail.

However the following example can use `inlateout` since the output is only modified after all input registers have been read:
This is because in optimized cases, the compiler is free to allocate the same register for inputs `b` and `c` since it knows that they have the same value. Furthermore, when `inlateout` is used, `a` and `c` could be allocated to the same register, in which case the first `add` instruction would overwrite the initial load from variable `c`. This is in contrast to how using `inout(reg) a` ensures a separate register is allocated for `a`.

However, the following example can use `inlateout` since the output is only modified after all input registers have been read:

```rust
# #[cfg(target_arch = "x86_64")] {
Expand Down

0 comments on commit 914a935

Please sign in to comment.