about summary refs log tree commit diff
path: root/src/doc
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-06-19 09:15:14 -0700
committerGitHub <noreply@github.com>2020-06-19 09:15:14 -0700
commit687f929c9b320fcd11097aee2778e2fc81fa8536 (patch)
treeb976f46a42678bc48c3441491a6396e4124d76bc /src/doc
parent65c33ed7986d76fdefee6cf93081f77fdec2e0c8 (diff)
parentfd9ed30e4b19457cc7059d1b08832edd6d2cbfb8 (diff)
downloadrust-687f929c9b320fcd11097aee2778e2fc81fa8536.tar.gz
rust-687f929c9b320fcd11097aee2778e2fc81fa8536.zip
Rollup merge of #73364 - joshtriplett:inline-asm, r=Amanieu
asm: Allow multiple template string arguments; interpret them as newline-separated

Allow the `asm!` macro to accept a series of template arguments, and interpret them as if they were concatenated with a '\n' between them. This allows writing an `asm!` where each line of assembly appears in a separate template string argument.

This syntax makes it possible for rustfmt to reliably format and indent each line of assembly, without risking changes to the inside of a template string. It also avoids the complexity of having the user carefully format and indent a multi-line string (including where to put the surrounding quotes), and avoids the extra indentation and lines of a call to `concat!`.

For example, rewriting the second example from the [blog post on the new inline assembly syntax](https://blog.rust-lang.org/inside-rust/2020/06/08/new-inline-asm.html) using multiple template strings:

```rust

fn main() {
    let mut bits = [0u8; 64];
    for value in 0..=1024u64 {
        let popcnt;
        unsafe {
            asm!(
                "    popcnt {popcnt}, {v}",
                "2:",
                "    blsi rax, {v}",
                "    jz 1f",
                "    xor {v}, rax",
                "    tzcnt rax, rax",
                "    stosb",
                "    jmp 2b",
                "1:",
                v = inout(reg) value => _,
                popcnt = out(reg) popcnt,
                out("rax") _, // scratch
                inout("rdi") bits.as_mut_ptr() => _,
            );
        }
        println!("bits of {}: {:?}", value, &bits[0..popcnt]);
    }
}
```

Note that all the template strings must appear before all other arguments; you cannot, for instance, provide a series of template strings intermixed with the corresponding operands.
Diffstat (limited to 'src/doc')
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md57
1 files changed, 36 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 e8fb7716cb1..a941bc9348f 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -68,10 +68,13 @@ Let us see another example that also uses an input:
 let i: u64 = 3;
 let o: u64;
 unsafe {
-    asm!("
-        mov {0}, {1}
-        add {0}, {number}
-    ", out(reg) o, in(reg) i, number = const 5);
+    asm!(
+        "mov {0}, {1}",
+        "add {0}, {number}",
+        out(reg) o,
+        in(reg) i,
+        number = const 5,
+    );
 }
 assert_eq!(o, 8);
 ```
@@ -82,13 +85,18 @@ and then adding `5` to it.
 
 The example shows a few things:
 
-First we can see that inputs are declared by writing `in` instead of `out`.
+First, we can see that `asm!` allows multiple template string arguments; each
+one is treated as a separate line of assembly code, as if they were all joined
+together with newlines between them. This makes it easy to format assembly
+code.
+
+Second, we can see that inputs are declared by writing `in` instead of `out`.
 
-Second one of our operands has a type we haven't seen yet, `const`.
+Third, one of our operands has a type we haven't seen yet, `const`.
 This tells the compiler to expand this argument to value directly inside the assembly template.
 This is only possible for constants and literals.
 
-Third we can see that we can specify an argument number, or name as in any format string.
+Fourth, we can see that we can specify an argument number, or name as in any format string.
 For inline assembly templates this is particularly useful as arguments are often used more than once.
 For more complex inline assembly using this facility is generally recommended, as it improves
 readability, and allows reordering instructions without changing the argument order.
@@ -137,10 +145,13 @@ let mut a: u64 = 4;
 let b: u64 = 4;
 let c: u64 = 4;
 unsafe {
-    asm!("
-        add {0}, {1}
-        add {0}, {2}
-    ", inout(reg) a, in(reg) b, in(reg) c);
+    asm!(
+        "add {0}, {1}",
+        "add {0}, {2}",
+        inout(reg) a,
+        in(reg) b,
+        in(reg) c,
+    );
 }
 assert_eq!(a, 12);
 ```
@@ -233,7 +244,7 @@ unsafe {
         // ECX 0 selects the L0 cache information.
         inout("ecx") 0 => ecx,
         lateout("ebx") ebx,
-        lateout("edx") _
+        lateout("edx") _,
     );
 }
 
@@ -255,12 +266,14 @@ This can also be used with a general register class (e.g. `reg`) to obtain a scr
 // Multiply x by 6 using shifts and adds
 let mut x: u64 = 4;
 unsafe {
-    asm!("
-        mov {tmp}, {x}
-        shl {tmp}, 1
-        shl {x}, 2
-        add {x}, {tmp}
-    ", x = inout(reg) x, tmp = out(reg) _);
+    asm!(
+        "mov {tmp}, {x}",
+        "shl {tmp}, 1",
+        "shl {x}, 2",
+        "add {x}, {tmp}",
+        x = inout(reg) x,
+        tmp = out(reg) _,
+    );
 }
 assert_eq!(x, 4 * 6);
 ```
@@ -338,7 +351,7 @@ unsafe {
     asm!(
         "add {0}, {1}",
         inlateout(reg) a, in(reg) b,
-        options(pure, nomem, nostack)
+        options(pure, nomem, nostack),
     );
 }
 assert_eq!(a, 8);
@@ -371,17 +384,19 @@ reg_operand := dir_spec "(" reg_spec ")" operand_expr
 operand := reg_operand / "const" const_expr / "sym" path
 option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax"
 options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")"
+asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
 ```
 
 The macro will initially be supported only on ARM, AArch64, Hexagon, 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.
 
 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
 
-## Template string
+## Template string arguments
 
 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.
 
+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.
+
 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.
 
 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.