]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/library-features/asm.md
Add comments to hygiene tests
[rust.git] / src / doc / unstable-book / src / library-features / asm.md
1 # `asm`
2
3 The tracking issue for this feature is: [#72016]
4
5 [#72016]: https://github.com/rust-lang/rust/issues/72016
6
7 ------------------------
8
9 For extremely low-level manipulations and performance reasons, one
10 might wish to control the CPU directly. Rust supports using inline
11 assembly to do this via the `asm!` macro.
12
13 # Guide-level explanation
14 [guide-level-explanation]: #guide-level-explanation
15
16 Rust provides support for inline assembly via the `asm!` macro.
17 It can be used to embed handwritten assembly in the assembly output generated by the compiler.
18 Generally this should not be necessary, but might be where the required performance or timing
19 cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.
20
21 > **Note**: the examples here are given in x86/x86-64 assembly, but other architectures are also supported.
22
23 Inline assembly is currently supported on the following architectures:
24 - x86 and x86-64
25 - ARM
26 - AArch64
27 - RISC-V
28 - NVPTX
29 - PowerPC
30 - Hexagon
31 - MIPS32r2 and MIPS64r2
32 - wasm32
33 - BPF
34 - SPIR-V
35
36 ## Basic usage
37
38 Let us start with the simplest possible example:
39
40 ```rust,allow_fail
41 #![feature(asm)]
42 unsafe {
43     asm!("nop");
44 }
45 ```
46
47 This will insert a NOP (no operation) instruction into the assembly generated by the compiler.
48 Note that all `asm!` invocations have to be inside an `unsafe` block, as they could insert
49 arbitrary instructions and break various invariants. The instructions to be inserted are listed
50 in the first argument of the `asm!` macro as a string literal.
51
52 ## Inputs and outputs
53
54 Now inserting an instruction that does nothing is rather boring. Let us do something that
55 actually acts on data:
56
57 ```rust,allow_fail
58 #![feature(asm)]
59 let x: u64;
60 unsafe {
61     asm!("mov {}, 5", out(reg) x);
62 }
63 assert_eq!(x, 5);
64 ```
65
66 This will write the value `5` into the `u64` variable `x`.
67 You can see that the string literal we use to specify instructions is actually a template string.
68 It is governed by the same rules as Rust [format strings][format-syntax].
69 The arguments that are inserted into the template however look a bit different then you may
70 be familiar with. First we need to specify if the variable is an input or an output of the
71 inline assembly. In this case it is an output. We declared this by writing `out`.
72 We also need to specify in what kind of register the assembly expects the variable.
73 In this case we put it in an arbitrary general purpose register by specifying `reg`.
74 The compiler will choose an appropriate register to insert into
75 the template and will read the variable from there after the inline assembly finishes executing.
76
77 Let us see another example that also uses an input:
78
79 ```rust,allow_fail
80 #![feature(asm)]
81 let i: u64 = 3;
82 let o: u64;
83 unsafe {
84     asm!(
85         "mov {0}, {1}",
86         "add {0}, {number}",
87         out(reg) o,
88         in(reg) i,
89         number = const 5,
90     );
91 }
92 assert_eq!(o, 8);
93 ```
94
95 This will add `5` to the input in variable `i` and write the result to variable `o`.
96 The particular way this assembly does this is first copying the value from `i` to the output,
97 and then adding `5` to it.
98
99 The example shows a few things:
100
101 First, we can see that `asm!` allows multiple template string arguments; each
102 one is treated as a separate line of assembly code, as if they were all joined
103 together with newlines between them. This makes it easy to format assembly
104 code.
105
106 Second, we can see that inputs are declared by writing `in` instead of `out`.
107
108 Third, one of our operands has a type we haven't seen yet, `const`.
109 This tells the compiler to expand this argument to value directly inside the assembly template.
110 This is only possible for constants and literals.
111
112 Fourth, we can see that we can specify an argument number, or name as in any format string.
113 For inline assembly templates this is particularly useful as arguments are often used more than once.
114 For more complex inline assembly using this facility is generally recommended, as it improves
115 readability, and allows reordering instructions without changing the argument order.
116
117 We can further refine the above example to avoid the `mov` instruction:
118
119 ```rust,allow_fail
120 #![feature(asm)]
121 let mut x: u64 = 3;
122 unsafe {
123     asm!("add {0}, {number}", inout(reg) x, number = const 5);
124 }
125 assert_eq!(x, 8);
126 ```
127
128 We can see that `inout` is used to specify an argument that is both input and output.
129 This is different from specifying an input and output separately in that it is guaranteed to assign both to the same register.
130
131 It is also possible to specify different variables for the input and output parts of an `inout` operand:
132
133 ```rust,allow_fail
134 #![feature(asm)]
135 let x: u64 = 3;
136 let y: u64;
137 unsafe {
138     asm!("add {0}, {number}", inout(reg) x => y, number = const 5);
139 }
140 assert_eq!(y, 8);
141 ```
142
143 ## Late output operands
144
145 The Rust compiler is conservative with its allocation of operands. It is assumed that an `out`
146 can be written at any time, and can therefore not share its location with any other argument.
147 However, to guarantee optimal performance it is important to use as few registers as possible,
148 so they won't have to be saved and reloaded around the inline assembly block.
149 To achieve this Rust provides a `lateout` specifier. This can be used on any output that is
150 written only after all inputs have been consumed.
151 There is also a `inlateout` variant of this specifier.
152
153 Here is an example where `inlateout` *cannot* be used:
154
155 ```rust,allow_fail
156 #![feature(asm)]
157 let mut a: u64 = 4;
158 let b: u64 = 4;
159 let c: u64 = 4;
160 unsafe {
161     asm!(
162         "add {0}, {1}",
163         "add {0}, {2}",
164         inout(reg) a,
165         in(reg) b,
166         in(reg) c,
167     );
168 }
169 assert_eq!(a, 12);
170 ```
171
172 Here 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 to overwrite the value of `c` and cause the assembly code to produce the wrong result.
173
174 However the following example can use `inlateout` since the output is only modified after all input registers have been read:
175
176 ```rust,allow_fail
177 #![feature(asm)]
178 let mut a: u64 = 4;
179 let b: u64 = 4;
180 unsafe {
181     asm!("add {0}, {1}", inlateout(reg) a, in(reg) b);
182 }
183 assert_eq!(a, 8);
184 ```
185
186 As you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register.
187
188 ## Explicit register operands
189
190 Some instructions require that the operands be in a specific register.
191 Therefore, Rust inline assembly provides some more specific constraint specifiers.
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
194 ```rust,allow_fail,no_run
195 #![feature(asm)]
196 let cmd = 0xd1;
197 unsafe {
198     asm!("out 0x64, eax", in("eax") cmd);
199 }
200 ```
201
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.
203
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.
205
206 Consider this example which uses the x86 `mul` instruction:
207
208 ```rust,allow_fail
209 #![feature(asm)]
210 fn mul(a: u64, b: u64) -> u128 {
211     let lo: u64;
212     let hi: u64;
213
214     unsafe {
215         asm!(
216             // The x86 mul instruction takes rax as an implicit input and writes
217             // the 128-bit result of the multiplication to rax:rdx.
218             "mul {}",
219             in(reg) a,
220             inlateout("rax") b => lo,
221             lateout("rdx") hi
222         );
223     }
224
225     ((hi as u128) << 64) + lo as u128
226 }
227 ```
228
229 This uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result.
230 The only explicit operand is a register, that we fill from the variable `a`.
231 The second operand is implicit, and must be the `rax` register, which we fill from the variable `b`.
232 The lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`.
233 The higher 64 bits are stored in `rdx` from which we fill the variable `hi`.
234
235 ## Clobbered registers
236
237 In many cases inline assembly will modify state that is not needed as an output.
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.
239 This state is generally referred to as being "clobbered".
240 We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block.
241
242 ```rust,allow_fail
243 #![feature(asm)]
244 let ebx: u32;
245 let ecx: u32;
246
247 unsafe {
248     asm!(
249         "cpuid",
250         // EAX 4 selects the "Deterministic Cache Parameters" CPUID leaf
251         inout("eax") 4 => _,
252         // ECX 0 selects the L0 cache information.
253         inout("ecx") 0 => ecx,
254         lateout("ebx") ebx,
255         lateout("edx") _,
256     );
257 }
258
259 println!(
260     "L1 Cache: {}",
261     ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)
262 );
263 ```
264
265 In the example above we use the `cpuid` instruction to get the L1 cache size.
266 This instruction writes to `eax`, `ebx`, `ecx`, and `edx`, but for the cache size we only care about the contents of `ebx` and `ecx`.
267
268 However we still need to tell the compiler that `eax` and `edx` have been modified so that it can save any values that were in these registers before the asm. This is done by declaring these as outputs but with `_` instead of a variable name, which indicates that the output value is to be discarded.
269
270 This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
271
272 ```rust,allow_fail
273 #![feature(asm)]
274 // Multiply x by 6 using shifts and adds
275 let mut x: u64 = 4;
276 unsafe {
277     asm!(
278         "mov {tmp}, {x}",
279         "shl {tmp}, 1",
280         "shl {x}, 2",
281         "add {x}, {tmp}",
282         x = inout(reg) x,
283         tmp = out(reg) _,
284     );
285 }
286 assert_eq!(x, 4 * 6);
287 ```
288
289 ## Symbol operands and ABI clobbers
290
291 A special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.
292 This allows you to call a function or access a global variable without needing to keep its address in a register.
293
294 ```rust,allow_fail
295 #![feature(asm)]
296 extern "C" fn foo(arg: i32) -> i32 {
297     println!("arg = {}", arg);
298     arg * 2
299 }
300
301 fn call_foo(arg: i32) -> i32 {
302     unsafe {
303         let result;
304         asm!(
305             "call {}",
306             sym foo,
307             // 1st argument in rdi
308             in("rdi") arg,
309             // Return value in rax
310             out("rax") result,
311             // Mark all registers which are not preserved by the "C" calling
312             // convention as clobbered.
313             clobber_abi("C"),
314         );
315         result
316     }
317 }
318 ```
319
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.
321
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.
323
324 ## Register template modifiers
325
326 In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register).
327
328 By default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc).
329
330 This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
331
332 ```rust,allow_fail
333 #![feature(asm)]
334 let mut x: u16 = 0xab;
335
336 unsafe {
337     asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
338 }
339
340 assert_eq!(x, 0xabab);
341 ```
342
343 In this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 register (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.
344
345 Let us assume that the register allocator has chosen to allocate `x` in the `ax` register.
346 The `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.
347
348 If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
349
350 ## Memory address operands
351
352 Sometimes assembly instructions require operands passed via memory addresses/memory locations.
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:
355
356 ```rust,allow_fail
357 #![feature(asm, llvm_asm)]
358 # fn load_fpu_control_word(control: u16) {
359 unsafe {
360     asm!("fldcw [{}]", in(reg) &control, options(nostack));
361
362     // Previously this would have been written with the deprecated `llvm_asm!` like this
363     llvm_asm!("fldcw $0" :: "m" (control) :: "volatile");
364 }
365 # }
366 ```
367
368 ## Labels
369
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:
371
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 `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block.
379
380 ```rust,allow_fail
381 #![feature(asm)]
382
383 let mut a = 0;
384 unsafe {
385     asm!(
386         "mov {0}, 10",
387         "2:",
388         "sub {0}, 1",
389         "cmp {0}, 3",
390         "jle 2f",
391         "jmp 2b",
392         "2:",
393         "add {0}, 2",
394         out(reg) a
395     );
396 }
397 assert_eq!(a, 5);
398 ```
399
400 This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
401
402 This example shows a few things:
403
404 First that the same number can be used as a label multiple times in the same inline block.
405
406 Second, that when a numeric label is used as a reference (as an instruction operand, for example), the suffixes b (“backward”) or f (“forward”) should be added to the numeric label. It will then refer to the nearest label defined by this number in this direction.
407
408 [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
409 [an llvm bug]: https://bugs.llvm.org/show_bug.cgi?id=36144
410
411 ## Options
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.
414
415 Let's take our previous example of an `add` instruction:
416
417 ```rust,allow_fail
418 #![feature(asm)]
419 let mut a: u64 = 4;
420 let b: u64 = 4;
421 unsafe {
422     asm!(
423         "add {0}, {1}",
424         inlateout(reg) a, in(reg) b,
425         options(pure, nomem, nostack),
426     );
427 }
428 assert_eq!(a, 8);
429 ```
430
431 Options can be provided as an optional final argument to the `asm!` macro. We specified three options here:
432 - `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely.
433 - `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global).
434 - `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments.
435
436 These allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed.
437
438 See the reference for the full list of available options and their effects.
439
440 # Reference-level explanation
441 [reference-level-explanation]: #reference-level-explanation
442
443 Inline assembler is implemented as an unsafe macro `asm!()`.
444 The first argument to this macro is a template string literal used to build the final assembly.
445 The following arguments specify input and output operands.
446 When required, options are specified as the final argument.
447
448 The following ABNF specifies the general syntax:
449
450 ```text
451 dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout"
452 reg_spec := <register class> / "<explicit register>"
453 operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
454 reg_operand := dir_spec "(" reg_spec ")" operand_expr
455 operand := reg_operand / "const" const_expr / "sym" path
456 clobber_abi := "clobber_abi(" <abi> ")"
457 option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
458 options := "options(" option *["," option] [","] ")"
459 asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] *("," options) [","] ")"
460 ```
461
462 Inline assembly is currently supported on the following architectures:
463 - x86 and x86-64
464 - ARM
465 - AArch64
466 - RISC-V
467 - NVPTX
468 - PowerPC
469 - Hexagon
470 - MIPS32r2 and MIPS64r2
471 - wasm32
472 - BPF
473 - SPIR-V
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.
476
477 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
478
479 ## Template string arguments
480
481 The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.
482
483 An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.
484
485 As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.
486
487 Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
488
489 The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
490
491 The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
492
493 [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
494
495 ## Operand type
496
497 Several types of operands are supported:
498
499 * `in(<reg>) <expr>`
500   - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
501   - The allocated register will contain the value of `<expr>` at the start of the asm code.
502   - The allocated register must contain the same value at the end of the asm code (except if a `lateout` is allocated to the same register).
503 * `out(<reg>) <expr>`
504   - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
505   - The allocated register will contain an undefined value at the start of the asm code.
506   - `<expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.
507   - An underscore (`_`) may be specified instead of an expression, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
508 * `lateout(<reg>) <expr>`
509   - Identical to `out` except that the register allocator can reuse a register allocated to an `in`.
510   - You should only write to the register after all inputs are read, otherwise you may clobber an input.
511 * `inout(<reg>) <expr>`
512   - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
513   - The allocated register will contain the value of `<expr>` at the start of the asm code.
514   - `<expr>` must be a mutable initialized place expression, to which the contents of the allocated register is written to at the end of the asm code.
515 * `inout(<reg>) <in expr> => <out expr>`
516   - Same as `inout` except that the initial value of the register is taken from the value of `<in expr>`.
517   - `<out expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.
518   - An underscore (`_`) may be specified instead of an expression for `<out expr>`, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
519   - `<in expr>` and `<out expr>` may have different types.
520 * `inlateout(<reg>) <expr>` / `inlateout(<reg>) <in expr> => <out expr>`
521   - Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`).
522   - You should only write to the register after all inputs are read, otherwise you may clobber an input.
523 * `const <expr>`
524   - `<expr>` must be an integer constant expression.
525   - The value of the expression is formatted as a string and substituted directly into the asm template string.
526 * `sym <path>`
527   - `<path>` must refer to a `fn` or `static`.
528   - A mangled symbol name referring to the item is substituted into the asm template string.
529   - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
530   - `<path>` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.
531
532 Operand expressions are evaluated from left to right, just like function call arguments. After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.
533
534 ## Register operands
535
536 Input and output operands can be specified either as an explicit register or as a register class from which the register allocator can select a register. Explicit registers are specified as string literals (e.g. `"eax"`) while register classes are specified as identifiers (e.g. `reg`). Using string literals for register names enables support for architectures that use special characters in register names, such as MIPS (`$0`, `$1`, etc).
537
538 Note that explicit registers treat register aliases (e.g. `r14` vs `lr` on ARM) and smaller views of a register (e.g. `eax` vs `rax`) as equivalent to the base register. It is a compile-time error to use the same explicit register for two input operands or two output operands. Additionally, it is also a compile-time error to use overlapping registers (e.g. ARM VFP) in input operands or in output operands.
539
540 Only the following types are allowed as operands for inline assembly:
541 - Integers (signed and unsigned)
542 - Floating-point numbers
543 - Pointers (thin only)
544 - Function pointers
545 - SIMD vectors (structs defined with `#[repr(simd)]` and which implement `Copy`). This includes architecture-specific vector types defined in `std::arch` such as `__m128` (x86) or `int8x16_t` (ARM).
546
547 Here is the list of currently supported register classes:
548
549 | Architecture | Register class | Registers | LLVM constraint code |
550 | ------------ | -------------- | --------- | -------------------- |
551 | x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `bp`, `r[8-15]` (x86-64 only) | `r` |
552 | x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
553 | x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
554 | x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `bpl`, `r[8-15]b` | `q` |
555 | x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
556 | x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
557 | x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
558 | x86 | `kreg` | `k[1-7]` | `Yk` |
559 | x86 | `x87_reg` | `st([0-7])` | Only clobbers |
560 | x86 | `mmx_reg` | `mm[0-7]` | Only clobbers |
561 | AArch64 | `reg` | `x[0-30]` | `r` |
562 | AArch64 | `vreg` | `v[0-31]` | `w` |
563 | AArch64 | `vreg_low16` | `v[0-15]` | `x` |
564 | AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers |
565 | ARM | `reg` | `r[0-12]`, `r14` | `r` |
566 | ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
567 | ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
568 | ARM | `sreg` | `s[0-31]` | `t` |
569 | ARM | `sreg_low16` | `s[0-15]` | `x` |
570 | ARM | `dreg` | `d[0-31]` | `w` |
571 | ARM | `dreg_low16` | `d[0-15]` | `t` |
572 | ARM | `dreg_low8` | `d[0-8]` | `x` |
573 | ARM | `qreg` | `q[0-15]` | `w` |
574 | ARM | `qreg_low8` | `q[0-7]` | `t` |
575 | ARM | `qreg_low4` | `q[0-3]` | `x` |
576 | MIPS | `reg` | `$[2-25]` | `r` |
577 | MIPS | `freg` | `$f[0-31]` | `f` |
578 | NVPTX | `reg16` | None\* | `h` |
579 | NVPTX | `reg32` | None\* | `r` |
580 | NVPTX | `reg64` | None\* | `l` |
581 | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
582 | RISC-V | `freg` | `f[0-31]` | `f` |
583 | RISC-V | `vreg` | `v[0-31]` | Only clobbers |
584 | Hexagon | `reg` | `r[0-28]` | `r` |
585 | PowerPC | `reg` | `r[0-31]` | `r` |
586 | PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
587 | PowerPC | `freg` | `f[0-31]` | `f` |
588 | PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers |
589 | PowerPC | `xer` | `xer` | Only clobbers |
590 | wasm32 | `local` | None\* | `r` |
591 | BPF | `reg` | `r[0-10]` | `r` |
592 | BPF | `wreg` | `w[0-10]` | `w` |
593
594 > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
595 >
596 > Note #2: On x86-64 the high byte registers (e.g. `ah`) are not available in the `reg_byte` register class.
597 >
598 > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
599 >
600 > Note #4: WebAssembly doesn't have registers, so named registers are not supported.
601 >
602 > Note #5: Some register classes are marked as "Only clobbers" which means that they cannot be used for inputs or outputs, only clobbers of the form `out("reg") _` or `lateout("reg") _`.
603
604 Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
605
606 Each register class has constraints on which value types they can be used with. This is necessary because the way a value is loaded into a register depends on its type. For example, on big-endian systems, loading a `i32x4` and a `i8x16` into a SIMD register may result in different register contents even if the byte-wise memory representation of both values is identical. The availability of supported types for a particular register class may depend on what target features are currently enabled.
607
608 | Architecture | Register class | Target feature | Allowed types |
609 | ------------ | -------------- | -------------- | ------------- |
610 | x86-32 | `reg` | None | `i16`, `i32`, `f32` |
611 | x86-64 | `reg` | None | `i16`, `i32`, `f32`, `i64`, `f64` |
612 | x86 | `reg_byte` | None | `i8` |
613 | x86 | `xmm_reg` | `sse` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
614 | x86 | `ymm_reg` | `avx` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` |
615 | x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` <br> `i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` |
616 | x86 | `kreg` | `avx512f` | `i8`, `i16` |
617 | x86 | `kreg` | `avx512bw` | `i32`, `i64` |
618 | x86 | `mmx_reg` | N/A | Only clobbers |
619 | x86 | `x87_reg` | N/A | Only clobbers |
620 | AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
621 | AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
622 | AArch64 | `preg` | N/A | Only clobbers |
623 | ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` |
624 | ARM | `sreg` | `vfp2` | `i32`, `f32` |
625 | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
626 | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
627 | MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
628 | MIPS32 | `freg` | None | `f32`, `f64` |
629 | MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
630 | MIPS64 | `freg` | None | `f32`, `f64` |
631 | NVPTX | `reg16` | None | `i8`, `i16` |
632 | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
633 | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
634 | RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
635 | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
636 | RISC-V | `freg` | `f` | `f32` |
637 | RISC-V | `freg` | `d` | `f64` |
638 | RISC-V | `vreg` | N/A | Only clobbers |
639 | Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
640 | PowerPC | `reg` | None | `i8`, `i16`, `i32` |
641 | PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
642 | PowerPC | `freg` | None | `f32`, `f64` |
643 | PowerPC | `cr` | N/A | Only clobbers |
644 | PowerPC | `xer` | N/A | Only clobbers |
645 | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
646 | BPF | `reg` | None | `i8` `i16` `i32` `i64` |
647 | BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
648
649 > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
650
651 If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture.
652
653 When separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types.
654
655 ## Register names
656
657 Some registers have multiple names. These are all treated by the compiler as identical to the base register name. Here is the list of all supported register aliases:
658
659 | Architecture | Base register | Aliases |
660 | ------------ | ------------- | ------- |
661 | x86 | `ax` | `eax`, `rax` |
662 | x86 | `bx` | `ebx`, `rbx` |
663 | x86 | `cx` | `ecx`, `rcx` |
664 | x86 | `dx` | `edx`, `rdx` |
665 | x86 | `si` | `esi`, `rsi` |
666 | x86 | `di` | `edi`, `rdi` |
667 | x86 | `bp` | `bpl`, `ebp`, `rbp` |
668 | x86 | `sp` | `spl`, `esp`, `rsp` |
669 | x86 | `ip` | `eip`, `rip` |
670 | x86 | `st(0)` | `st` |
671 | x86 | `r[8-15]` | `r[8-15]b`, `r[8-15]w`, `r[8-15]d` |
672 | x86 | `xmm[0-31]` | `ymm[0-31]`, `zmm[0-31]` |
673 | AArch64 | `x[0-30]` | `w[0-30]` |
674 | AArch64 | `x29` | `fp` |
675 | AArch64 | `x30` | `lr` |
676 | AArch64 | `sp` | `wsp` |
677 | AArch64 | `xzr` | `wzr` |
678 | AArch64 | `v[0-31]` | `b[0-31]`, `h[0-31]`, `s[0-31]`, `d[0-31]`, `q[0-31]` |
679 | ARM | `r[0-3]` | `a[1-4]` |
680 | ARM | `r[4-9]` | `v[1-6]` |
681 | ARM | `r9` | `rfp` |
682 | ARM | `r10` | `sl` |
683 | ARM | `r11` | `fp` |
684 | ARM | `r12` | `ip` |
685 | ARM | `r13` | `sp` |
686 | ARM | `r14` | `lr` |
687 | ARM | `r15` | `pc` |
688 | RISC-V | `x0` | `zero` |
689 | RISC-V | `x1` | `ra` |
690 | RISC-V | `x2` | `sp` |
691 | RISC-V | `x3` | `gp` |
692 | RISC-V | `x4` | `tp` |
693 | RISC-V | `x[5-7]` | `t[0-2]` |
694 | RISC-V | `x8` | `fp`, `s0` |
695 | RISC-V | `x9` | `s1` |
696 | RISC-V | `x[10-17]` | `a[0-7]` |
697 | RISC-V | `x[18-27]` | `s[2-11]` |
698 | RISC-V | `x[28-31]` | `t[3-6]` |
699 | RISC-V | `f[0-7]` | `ft[0-7]` |
700 | RISC-V | `f[8-9]` | `fs[0-1]` |
701 | RISC-V | `f[10-17]` | `fa[0-7]` |
702 | RISC-V | `f[18-27]` | `fs[2-11]` |
703 | RISC-V | `f[28-31]` | `ft[8-11]` |
704 | Hexagon | `r29` | `sp` |
705 | Hexagon | `r30` | `fr` |
706 | Hexagon | `r31` | `lr` |
707 | BPF | `r[0-10]` | `w[0-10]` |
708
709 Some registers cannot be used for input or output operands:
710
711 | Architecture | Unsupported register | Reason |
712 | ------------ | -------------------- | ------ |
713 | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
714 | All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. |
715 | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
716 | All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `r19` (Hexagon), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
717 | x86 | `k0` | This is a constant zero register which can't be modified. |
718 | x86 | `ip` | This is the program counter, not a real register. |
719 | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
720 | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
721 | AArch64 | `xzr` | This is a constant zero register which can't be modified. |
722 | ARM | `pc` | This is the program counter, not a real register. |
723 | ARM | `r9` | This is a reserved register on some ARM targets. |
724 | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
725 | MIPS | `$1` or `$at` | Reserved for assembler. |
726 | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
727 | MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
728 | MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
729 | RISC-V | `x0` | This is a constant zero register which can't be modified. |
730 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
731 | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
732
733 In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer
734 - The frame pointer and LLVM base pointer on all architectures.
735 - `r9` on ARM.
736 - `x18` on AArch64.
737
738 ## Template modifiers
739
740 The placeholders can be augmented by modifiers which are specified after the `:` in the curly braces. These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string. Only one modifier is allowed per template placeholder.
741
742 The supported modifiers are a subset of LLVM's (and GCC's) [asm template argument modifiers][llvm-argmod], but do not use the same letter codes.
743
744 | Architecture | Register class | Modifier | Example output | LLVM modifier |
745 | ------------ | -------------- | -------- | -------------- | ------------- |
746 | x86-32 | `reg` | None | `eax` | `k` |
747 | x86-64 | `reg` | None | `rax` | `q` |
748 | x86-32 | `reg_abcd` | `l` | `al` | `b` |
749 | x86-64 | `reg` | `l` | `al` | `b` |
750 | x86 | `reg_abcd` | `h` | `ah` | `h` |
751 | x86 | `reg` | `x` | `ax` | `w` |
752 | x86 | `reg` | `e` | `eax` | `k` |
753 | x86-64 | `reg` | `r` | `rax` | `q` |
754 | x86 | `reg_byte` | None | `al` / `ah` | None |
755 | x86 | `xmm_reg` | None | `xmm0` | `x` |
756 | x86 | `ymm_reg` | None | `ymm0` | `t` |
757 | x86 | `zmm_reg` | None | `zmm0` | `g` |
758 | x86 | `*mm_reg` | `x` | `xmm0` | `x` |
759 | x86 | `*mm_reg` | `y` | `ymm0` | `t` |
760 | x86 | `*mm_reg` | `z` | `zmm0` | `g` |
761 | x86 | `kreg` | None | `k1` | None |
762 | AArch64 | `reg` | None | `x0` | `x` |
763 | AArch64 | `reg` | `w` | `w0` | `w` |
764 | AArch64 | `reg` | `x` | `x0` | `x` |
765 | AArch64 | `vreg` | None | `v0` | None |
766 | AArch64 | `vreg` | `v` | `v0` | None |
767 | AArch64 | `vreg` | `b` | `b0` | `b` |
768 | AArch64 | `vreg` | `h` | `h0` | `h` |
769 | AArch64 | `vreg` | `s` | `s0` | `s` |
770 | AArch64 | `vreg` | `d` | `d0` | `d` |
771 | AArch64 | `vreg` | `q` | `q0` | `q` |
772 | ARM | `reg` | None | `r0` | None |
773 | ARM | `sreg` | None | `s0` | None |
774 | ARM | `dreg` | None | `d0` | `P` |
775 | ARM | `qreg` | None | `q0` | `q` |
776 | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
777 | MIPS | `reg` | None | `$2` | None |
778 | MIPS | `freg` | None | `$f0` | None |
779 | NVPTX | `reg16` | None | `rs0` | None |
780 | NVPTX | `reg32` | None | `r0` | None |
781 | NVPTX | `reg64` | None | `rd0` | None |
782 | RISC-V | `reg` | None | `x1` | None |
783 | RISC-V | `freg` | None | `f0` | None |
784 | Hexagon | `reg` | None | `r0` | None |
785 | PowerPC | `reg` | None | `0` | None |
786 | PowerPC | `reg_nonzero` | None | `3` | `b` |
787 | PowerPC | `freg` | None | `0` | None |
788
789 > Notes:
790 > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
791 > - on x86: our behavior for `reg` with no modifiers differs from what GCC does. GCC will infer the modifier based on the operand value type, while we default to the full register size.
792 > - on x86 `xmm_reg`: the `x`, `t` and `g` LLVM modifiers are not yet implemented in LLVM (they are supported by GCC only), but this should be a simple change.
793
794 As stated in the previous section, passing an input value smaller than the register width will result in the upper bits of the register containing undefined values. This is not a problem if the inline asm only accesses the lower bits of the register, which can be done by using a template modifier to use a subregister name in the asm code (e.g. `ax` instead of `rax`). Since this an easy pitfall, the compiler will suggest a template modifier to use where appropriate given the input type. If all references to an operand already have modifiers then the warning is suppressed for that operand.
795
796 [llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
797
798 ## ABI clobbers
799
800 The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list.
801
802 Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output.
803 The following ABIs can be used with `clobber_abi`:
804
805 | Architecture | ABI name | Clobbered registers |
806 | ------------ | -------- | ------------------- |
807 | x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` |
808 | x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` |
809 | x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` |
810 | AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x30`, `v[0-31]`, `p[0-15]`, `ffr` |
811 | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` |
812 | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` |
813
814 The list of clobbered registers for each ABI is updated in rustc as architectures gain new registers: this ensures that `asm` clobbers will continue to be correct when LLVM starts using these new registers in its generated code.
815
816 ## Options
817
818 Flags are used to further influence the behavior of the inline assembly block.
819 Currently the following options are defined:
820 - `pure`: The `asm` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used.
821 - `nomem`: The `asm` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm` block since it knows that they are not read or written to by the `asm`.
822 - `readonly`: The `asm` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm` block since it knows that they are not written to by the `asm`.
823 - `preserves_flags`: The `asm` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.
824 - `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
825 - `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
826 - `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
827 - `raw`: This causes the template string to be parsed as a raw assembly string, with no special handling for `{` and `}`. This is primarily useful when including raw assembly code from an external file using `include_str!`.
828
829 The compiler performs some additional checks on options:
830 - The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.
831 - The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted.
832 - It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`).
833 - It is a compile-time error to specify `noreturn` on an asm block with outputs.
834
835 ## Rules for inline assembly
836
837 - Any registers not specified as inputs will contain an undefined value on entry to the asm block.
838   - An "undefined value" in the context of inline assembly means that the register can (non-deterministically) have any one of the possible values allowed by the architecture. Notably it is not the same as an LLVM `undef` which can have a different value every time you read it (since such a concept does not exist in assembly code).
839 - Any registers not specified as outputs must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.
840   - This only applies to registers which can be specified as an input or output. Other registers follow target-specific rules.
841   - 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.
842 - Behavior is undefined if execution unwinds out of an asm block.
843   - This also applies if the assembly code calls a function which then unwinds.
844 - The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
845   - Refer to the unsafe code guidelines for the exact rules.
846   - If the `readonly` option is set, then only memory reads are allowed.
847   - If the `nomem` option is set then no reads or writes to memory are allowed.
848   - These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.
849 - The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
850   - This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves.
851   - Runtime code patching is allowed, via target-specific mechanisms (outside the scope of this RFC).
852 - Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer.
853   - On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
854   - You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page).
855   - You should adjust the stack pointer when allocating stack memory as required by the target ABI.
856   - The stack pointer must be restored to its original value before leaving the asm block.
857 - If the `noreturn` option is set then behavior is undefined if execution falls through to the end of the asm block.
858 - If the `pure` option is set then behavior is undefined if the `asm` has side-effects other than its direct outputs. Behavior is also undefined if two executions of the `asm` code with the same inputs result in different outputs.
859   - When used with the `nomem` option, "inputs" are just the direct inputs of the `asm!`.
860   - When used with the `readonly` option, "inputs" comprise the direct inputs of the `asm!` and any memory that the `asm!` block is allowed to read.
861 - These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
862   - x86
863     - Status flags in `EFLAGS` (CF, PF, AF, ZF, SF, OF).
864     - Floating-point status word (all).
865     - Floating-point exception flags in `MXCSR` (PE, UE, OE, ZE, DE, IE).
866   - ARM
867     - Condition flags in `CPSR` (N, Z, C, V)
868     - Saturation flag in `CPSR` (Q)
869     - Greater than or equal flags in `CPSR` (GE).
870     - Condition flags in `FPSCR` (N, Z, C, V)
871     - Saturation flag in `FPSCR` (QC)
872     - Floating-point exception flags in `FPSCR` (IDC, IXC, UFC, OFC, DZC, IOC).
873   - AArch64
874     - Condition flags (`NZCV` register).
875     - Floating-point status (`FPSR` register).
876   - RISC-V
877     - Floating-point exception flags in `fcsr` (`fflags`).
878     - Vector extension state (`vtype`, `vl`, `vcsr`).
879 - On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit.
880   - Behavior is undefined if the direction flag is set on exiting an asm block.
881 - The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block.
882   - This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers.
883   - When returning to a different `asm!` block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the `asm!` block that you are *exiting*.
884     - You cannot exit an `asm!` block that has not been entered. Neither can you exit an `asm!` block that has already been exited.
885     - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
886     - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
887 - You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
888
889 > **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.