You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Auto merge of #88281 - asquared31415:asm-docs, r=Amanieu
Update unstable docs for `asm!` macro
This adds documentation that SPIR-V is supported, expands on the restrictions for labels, and has some minor cleanups or clarifications.
r? `@joshtriplett`
Copy file name to clipboardexpand all lines: src/doc/unstable-book/src/library-features/asm.md
+20-19
Original file line number
Diff line number
Diff line change
@@ -31,6 +31,7 @@ Inline assembly is currently supported on the following architectures:
31
31
- MIPS32r2 and MIPS64r2
32
32
- wasm32
33
33
- BPF
34
+
- SPIR-V
34
35
35
36
## Basic usage
36
37
@@ -188,8 +189,7 @@ As you can see, this assembly fragment will still work correctly if `a` and `b`
188
189
189
190
Some instructions require that the operands be in a specific register.
190
191
Therefore, Rust inline assembly provides some more specific constraint specifiers.
191
-
While `reg` is generally available on any architecture, these are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi`
192
-
among others can be addressed by their name.
192
+
While `reg` is generally available on any architecture, explicit registers are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi` among others can be addressed by their name.
193
193
194
194
```rust,allow_fail,no_run
195
195
#![feature(asm)]
@@ -199,11 +199,9 @@ unsafe {
199
199
}
200
200
```
201
201
202
-
In this example we call the `out` instruction to output the content of the `cmd` variable
203
-
to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand
204
-
we had to use the `eax` constraint specifier.
202
+
In this example we call the `out` instruction to output the content of the `cmd` variable to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand we had to use the `eax` constraint specifier.
205
203
206
-
Note that unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.
204
+
> **Note**: unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.
207
205
208
206
Consider this example which uses the x86 `mul` instruction:
209
207
@@ -237,11 +235,9 @@ The higher 64 bits are stored in `rdx` from which we fill the variable `hi`.
237
235
## Clobbered registers
238
236
239
237
In many cases inline assembly will modify state that is not needed as an output.
240
-
Usually this is either because we have to use a scratch register in the assembly,
241
-
or instructions modify state that we don't need to further examine.
238
+
Usually this is either because we have to use a scratch register in the assembly or because instructions modify state that we don't need to further examine.
242
239
This state is generally referred to as being "clobbered".
243
-
We need to tell the compiler about this since it may need to save and restore this state
244
-
around the inline assembly block.
240
+
We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block.
Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`:
325
-
the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
320
+
Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`: the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
326
321
327
322
By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered.
328
323
@@ -355,9 +350,8 @@ If you use a smaller data type (e.g. `u16`) with an operand and forget the use t
355
350
## Memory address operands
356
351
357
352
Sometimes assembly instructions require operands passed via memory addresses/memory locations.
358
-
You have to manually use the memory address syntax specified by the respectively architectures.
359
-
For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]`
360
-
to indicate they are memory operands:
353
+
You have to manually use the memory address syntax specified by the target architecture.
354
+
For example, on x86/x86_64 using intel assembly syntax, you should wrap inputs/outputs in `[]` to indicate they are memory operands:
361
355
362
356
```rust,allow_fail
363
357
#![feature(asm, llvm_asm)]
@@ -373,9 +367,15 @@ unsafe {
373
367
374
368
## Labels
375
369
376
-
The compiler is allowed to instantiate multiple copies an `asm!` block, for example when the function containing it is inlined in multiple places. As a consequence, you should only use GNU assembler [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
370
+
Any reuse of a named label, local or otherwise, can result in a assembler or linker error or may cause other strange behavior. Reuse of a named label can happen in a variety of ways including:
377
371
378
-
Moreover, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values.
372
+
- explicitly: using a label more than once in one `asm!` block, or multiple times across blocks
373
+
- implicitly via inlining: the compiler is allowed to instantiate multiple copies of an `asm!` block, for example when the function containing it is inlined in multiple places.
374
+
- implicitly via LTO: LTO can cause code from *other crates* to be placed in the same codegen unit, and so could bring in arbitrary labels
375
+
376
+
As a consequence, you should only use GNU assembler **numeric**[local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
377
+
378
+
Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `option(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_`asm!` block.
379
379
380
380
```rust,allow_fail
381
381
#![feature(asm)]
@@ -410,7 +410,7 @@ Second, that when a numeric label is used as a reference (as an instruction oper
410
410
411
411
## Options
412
412
413
-
By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
413
+
By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However, in many cases it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
414
414
415
415
Let's take our previous example of an `add` instruction:
416
416
@@ -470,6 +470,7 @@ Inline assembly is currently supported on the following architectures:
470
470
- MIPS32r2 and MIPS64r2
471
471
- wasm32
472
472
- BPF
473
+
- SPIR-V
473
474
474
475
Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
475
476
@@ -836,7 +837,7 @@ The compiler performs some additional checks on options:
836
837
- Note that a `lateout` may be allocated to the same register as an `in`, in which case this rule does not apply. Code should not rely on this however since it depends on the results of register allocation.
837
838
- Behavior is undefined if execution unwinds out of an asm block.
838
839
- This also applies if the assembly code calls a function which then unwinds.
839
-
- The set of memory locations that assembly code is allowed the read and write are the same as those allowed for an FFI function.
840
+
- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
840
841
- Refer to the unsafe code guidelines for the exact rules.
841
842
- If the `readonly` option is set, then only memory reads are allowed.
842
843
- If the `nomem` option is set then no reads or writes to memory are allowed.
0 commit comments