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.
This commit is contained in:
Manish Goregaokar 2020-06-19 09:15:14 -07:00 committed by GitHub
commit 687f929c9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 571 additions and 179 deletions

View file

@ -22,5 +22,13 @@ pub fn main() {
asm!("{0}", inout(reg) b);
asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
asm!("", out("al") _, lateout("rbx") _);
asm!("inst1\ninst2");
asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
asm!("inst1\ninst2");
asm!("inst1\ninst2");
asm!("inst1\n\tinst2");
asm!("inst1\ninst2\ninst3\ninst4");
}
}

View file

@ -16,5 +16,14 @@ pub fn main() {
asm!("{name}", name = inout(reg) b);
asm!("{} {}", out(reg) _, inlateout(reg) b => _);
asm!("", out("al") _, lateout("rbx") _);
asm!("inst1", "inst2");
asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b);
asm!("inst1
inst2");
asm!("inst1\ninst2");
asm!("inst1\n\tinst2");
asm!("inst1\ninst2", "inst3\ninst4");
}
}

View file

@ -13,7 +13,7 @@ fn main() {
asm!("{}" foo);
//~^ ERROR expected token: `,`
asm!("{}", foo);
//~^ ERROR expected one of
//~^ ERROR expected operand, options, or additional template string
asm!("{}", in foo);
//~^ ERROR expected `(`, found `foo`
asm!("{}", in(reg foo));
@ -52,5 +52,13 @@ fn main() {
//~^ ERROR named arguments cannot follow explicit register arguments
asm!("{1}", in("eax") foo, const bar);
//~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
asm!("", options(), "");
//~^ ERROR expected one of
asm!("{}", in(reg) foo, "{}", out(reg) foo);
//~^ ERROR expected one of
asm!(format!("{{{}}}", 0), in(reg) foo);
//~^ ERROR asm template must be a string literal
asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
//~^ ERROR asm template must be a string literal
}
}

View file

@ -16,11 +16,11 @@ error: expected token: `,`
LL | asm!("{}" foo);
| ^^^ expected `,`
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo`
error: expected operand, options, or additional template string
--> $DIR/parse-error.rs:15:20
|
LL | asm!("{}", foo);
| ^^^ expected one of 8 possible tokens
| ^^^ expected operand, options, or additional template string
error: expected `(`, found `foo`
--> $DIR/parse-error.rs:17:23
@ -160,5 +160,33 @@ LL | asm!("{1}", in("eax") foo, const bar);
| |
| explicit register argument
error: aborting due to 24 previous errors
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
--> $DIR/parse-error.rs:55:29
|
LL | asm!("", options(), "");
| ^^ expected one of 8 possible tokens
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
--> $DIR/parse-error.rs:57:33
|
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
| ^^^^ expected one of 8 possible tokens
error: asm template must be a string literal
--> $DIR/parse-error.rs:59:14
|
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
--> $DIR/parse-error.rs:61:21
|
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 28 previous errors

View file

@ -40,5 +40,85 @@ fn main() {
asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
//~^ WARN: scale factor without index register is ignored
asm!(
"invalid_instruction",
);
//~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
"mov eax, eax",
"invalid_instruction",
"mov eax, eax",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
"mov eax, eax\n",
"invalid_instruction",
"mov eax, eax",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
"mov eax, eax",
concat!("invalid", "_", "instruction"),
"mov eax, eax",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
concat!("mov eax", ", ", "eax"),
concat!("invalid", "_", "instruction"),
concat!("mov eax", ", ", "eax"),
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
// Make sure template strings get separated
asm!(
"invalid_instruction1",
"invalid_instruction2",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
asm!(
concat!(
"invalid", "_", "instruction1", "\n",
"invalid", "_", "instruction2",
),
);
//~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
asm!(
concat!(
"invalid", "_", "instruction1", "\n",
"invalid", "_", "instruction2",
),
concat!(
"invalid", "_", "instruction3", "\n",
"invalid", "_", "instruction4",
),
);
//~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
//~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
//~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
asm!(
concat!(
"invalid", "_", "instruction1", "\n",
"invalid", "_", "instruction2", "\n",
),
concat!(
"invalid", "_", "instruction3", "\n",
"invalid", "_", "instruction4", "\n",
),
);
//~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
//~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
//~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
}
}

View file

@ -82,5 +82,209 @@ note: instantiated into assembly here
LL | movaps %xmm3, (%esi, 2)
| ^
error: aborting due to 6 previous errors; 1 warning emitted
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:45:14
|
LL | "invalid_instruction",
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:51:14
|
LL | "invalid_instruction",
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:58:14
|
LL | "invalid_instruction",
| ^
|
note: instantiated into assembly here
--> <inline asm>:4:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:65:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:72:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:79:14
|
LL | "invalid_instruction1",
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:80:14
|
LL | "invalid_instruction2",
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:86:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:86:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
--> $DIR/srcloc.rs:99:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:4:1
|
LL | invalid_instruction3
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
--> $DIR/srcloc.rs:99:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:5:1
|
LL | invalid_instruction4
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
--> $DIR/srcloc.rs:114:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:5:1
|
LL | invalid_instruction3
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
--> $DIR/srcloc.rs:114:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:6:1
|
LL | invalid_instruction4
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 23 previous errors; 1 warning emitted