Skip to content

Commit 13edc17

Browse files
committed
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`
2 parents dbb0fe9 + 8769b99 commit 13edc17

File tree

1 file changed

+20
-19
lines changed
  • src/doc/unstable-book/src/library-features

1 file changed

+20
-19
lines changed

src/doc/unstable-book/src/library-features/asm.md

+20-19
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Inline assembly is currently supported on the following architectures:
3131
- MIPS32r2 and MIPS64r2
3232
- wasm32
3333
- BPF
34+
- SPIR-V
3435

3536
## Basic usage
3637

@@ -188,8 +189,7 @@ As you can see, this assembly fragment will still work correctly if `a` and `b`
188189

189190
Some instructions require that the operands be in a specific register.
190191
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.
193193

194194
```rust,allow_fail,no_run
195195
#![feature(asm)]
@@ -199,11 +199,9 @@ unsafe {
199199
}
200200
```
201201

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.
205203

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.
207205
208206
Consider this example which uses the x86 `mul` instruction:
209207

@@ -237,11 +235,9 @@ The higher 64 bits are stored in `rdx` from which we fill the variable `hi`.
237235
## Clobbered registers
238236

239237
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.
242239
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.
245241

246242
```rust,allow_fail
247243
#![feature(asm)]
@@ -321,8 +317,7 @@ fn call_foo(arg: i32) -> i32 {
321317
}
322318
```
323319

324-
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.
326321

327322
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.
328323

@@ -355,9 +350,8 @@ If you use a smaller data type (e.g. `u16`) with an operand and forget the use t
355350
## Memory address operands
356351

357352
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:
361355

362356
```rust,allow_fail
363357
#![feature(asm, llvm_asm)]
@@ -373,9 +367,15 @@ unsafe {
373367

374368
## Labels
375369

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:
377371

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.
379379

380380
```rust,allow_fail
381381
#![feature(asm)]
@@ -410,7 +410,7 @@ Second, that when a numeric label is used as a reference (as an instruction oper
410410

411411
## Options
412412

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.
414414

415415
Let's take our previous example of an `add` instruction:
416416

@@ -470,6 +470,7 @@ Inline assembly is currently supported on the following architectures:
470470
- MIPS32r2 and MIPS64r2
471471
- wasm32
472472
- BPF
473+
- SPIR-V
473474

474475
Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
475476

@@ -836,7 +837,7 @@ The compiler performs some additional checks on options:
836837
- 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.
837838
- Behavior is undefined if execution unwinds out of an asm block.
838839
- 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.
840841
- Refer to the unsafe code guidelines for the exact rules.
841842
- If the `readonly` option is set, then only memory reads are allowed.
842843
- If the `nomem` option is set then no reads or writes to memory are allowed.

0 commit comments

Comments
 (0)