Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asm: Allow multiple template string arguments; interpret them as newline-separated #73364

Merged
merged 4 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 36 additions & 21 deletions src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
```
Expand All @@ -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.
Expand Down Expand Up @@ -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);
```
Expand Down Expand Up @@ -233,7 +244,7 @@ unsafe {
// ECX 0 selects the L0 cache information.
inout("ecx") 0 => ecx,
lateout("ebx") ebx,
lateout("edx") _
lateout("edx") _,
);
}

Expand All @@ -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);
```
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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, 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.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_ast/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1914,7 +1914,7 @@ impl fmt::Display for InlineAsmTemplatePiece {
match c {
'{' => f.write_str("{{")?,
'}' => f.write_str("}}")?,
_ => write!(f, "{}", c.escape_debug())?,
_ => c.fmt(f)?,
}
}
Ok(())
Expand Down
Loading