about summary refs log tree commit diff
path: root/src/doc
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2021-07-29 13:43:26 +0200
committerAmanieu d'Antras <amanieu@gmail.com>2021-08-12 12:43:11 +0100
commit3fd463a5ca98c54b4e79271280c69ce5468e1173 (patch)
treea89ee858ba88f4d0866b4e11093fd3dc850dacb5 /src/doc
parent2f4612260d35ef162c088b6b1a87f1e75717acb6 (diff)
downloadrust-3fd463a5ca98c54b4e79271280c69ce5468e1173.tar.gz
rust-3fd463a5ca98c54b4e79271280c69ce5468e1173.zip
Add support for clobber_abi to asm!
Diffstat (limited to 'src/doc')
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md70
1 files changed, 49 insertions, 21 deletions
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index 539499cc568..220b74ca6e6 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -290,38 +290,33 @@ unsafe {
 assert_eq!(x, 4 * 6);
 ```
 
-## Symbol operands
+## Symbol operands and ABI clobbers
 
 A special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.
 This allows you to call a function or access a global variable without needing to keep its address in a register.
 
 ```rust,allow_fail
 #![feature(asm)]
-extern "C" fn foo(arg: i32) {
+extern "C" fn foo(arg: i32) -> i32 {
     println!("arg = {}", arg);
+    arg * 2
 }
 
-fn call_foo(arg: i32) {
+fn call_foo(arg: i32) -> i32 {
     unsafe {
+        let result;
         asm!(
             "call {}",
             sym foo,
-            // 1st argument in rdi, which is caller-saved
-            inout("rdi") arg => _,
-            // All caller-saved registers must be marked as clobbered
-            out("rax") _, out("rcx") _, out("rdx") _, out("rsi") _,
-            out("r8") _, out("r9") _, out("r10") _, out("r11") _,
-            out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
-            out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
-            out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
-            out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
-            // Also mark AVX-512 registers as clobbered. This is accepted by the
-            // compiler even if AVX-512 is not enabled on the current target.
-            out("xmm16") _, out("xmm17") _, out("xmm18") _, out("xmm19") _,
-            out("xmm20") _, out("xmm21") _, out("xmm22") _, out("xmm23") _,
-            out("xmm24") _, out("xmm25") _, out("xmm26") _, out("xmm27") _,
-            out("xmm28") _, out("xmm29") _, out("xmm30") _, out("xmm31") _,
-        )
+            // 1st argument in rdi
+            in("rdi") arg,
+            // Return value in rax
+            out("rax") result,
+            // Mark all registers which are not preserved by the "C" calling
+            // convention as clobbered.
+            clobber_abi("C"),
+        );
+        result
     }
 }
 ```
@@ -329,6 +324,8 @@ fn call_foo(arg: i32) {
 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.
 
+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.
+
 ## Register template modifiers
 
 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).
@@ -456,12 +453,25 @@ reg_spec := <register class> / "<explicit register>"
 operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
 reg_operand := dir_spec "(" reg_spec ")" operand_expr
 operand := reg_operand / "const" const_expr / "sym" path
+clobber_abi := "clobber_abi(" <abi> ")"
 option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
 options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
+asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi]  ["," options] [","] ")"
 ```
 
-The macro will initially be supported only on ARM, AArch64, Hexagon, PowerPC, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
+Inline assembly is currently supported on the following architectures:
+- x86 and x86-64
+- ARM
+- AArch64
+- RISC-V
+- NVPTX
+- PowerPC
+- Hexagon
+- MIPS32r2 and MIPS64r2
+- wasm32
+- BPF
+
+Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
 
 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
 
@@ -780,6 +790,24 @@ As stated in the previous section, passing an input value smaller than the regis
 
 [llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
 
+## ABI clobbers
+
+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.
+
+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.
+The following ABIs can be used with `clobber_abi`:
+
+| Architecture | ABI name | Clobbered registers |
+| ------------ | -------- | ------------------- |
+| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `st([0-7])` |
+| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `st([0-7])` |
+| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `st([0-7])` |
+| AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x30`, `v[0-31]`, `p[0-15]`, `ffr` |
+| ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` |
+| 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]` |
+
+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.
+
 ## Options
 
 Flags are used to further influence the behavior of the inline assembly block.