- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.9k
Description
Consider the following code:
use std::arch::asm;
#[inline(never)]
pub fn my_test(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let mut g = 3;
    unsafe {
        asm!(
            "mov {a}, {b}",
            "xor {a}, {c}",
            "and {a}, {d}",
            "or {a}, {e}",
            "not {f}",
            "add {a}, {f}",
            "sub {a}, {g}",
            "mov {g}, {a}",
            a = in(reg) a,
            b = in(reg) b,
            c = in(reg) c,
            d = in(reg) d,
            e = out(reg) _,
            f = out(reg) _,
            g = inout(reg) g
        )
    }
    g
}which uses 7 registers. If we try to compile this on i686-pc-windows-msvc, in principle there are 7 general registers, but Rust Reference mentions that ebp and esi would be reserved, so I expect a compilation error.
We can put this in a lib.rs, and in main.rs we put:
use asm_test::my_test;
fn main() {
    println!("{}", my_test(1, 2, 3, 4));
}Instead, when compiling in release mode using cargo build --release --target i686-pc-windows-msvc, it compiles. cargo asm --lib --target i686-pc-windows-msvc reveals that the compiler does allocate esi and ebp.
cargo asm output
.section .text,"xr",one_only,asm_test::my_test
        .globl  asm_test::my_test
        .p2align        4, 0x90
asm_test::my_test:
Lfunc_begin0:
        .cv_func_id 0
        .cv_file        1 "R:\\asm-test\\src\\lib.rs" "D7E84472A8BA4CD0C091D8930D59F9C5C684E1A6" 2
        .cv_loc 0 1 3 0
        .cv_fpo_proc    asm_test::my_test 16
        push ebp
        .cv_fpo_pushreg ebp
        push ebx
        .cv_fpo_pushreg ebx
        push edi
        .cv_fpo_pushreg edi
        push esi
        .cv_fpo_pushreg esi
        .cv_fpo_endprologue
        mov ecx, dword ptr [esp + 20]
        mov edx, dword ptr [esp + 24]
        mov esi, dword ptr [esp + 28]
        mov edi, dword ptr [esp + 32]
        mov eax, 3
        .cv_loc 0 1 6 0
        #APP
        mov ecx, edx
        xor ecx, esi
        and ecx, edi
        or ecx, ebx
        not ebp
        add ecx, ebp
        sub ecx, eax
        mov eax, ecx
        #NO_APP
        .cv_loc 0 1 26 0
        pop esi
        pop edi
        pop ebx
        pop ebp
        ret
        .cv_fpo_endprocHowever, if we change #[inline(never)] to #[inline], the compiler correctly displays:
error: inline assembly requires more registers than available
I would expect a compilation error in both cases, and a guarantee that neither esi nor ebp gets allocated.
I haven't tried on x86_64 target yet simply because the number of general registers is a lot. I could try it later today.
Meta
Tried on both stable and nightly
rustc --version --verbose:
rustc 1.66.1 (90743e729 2023-01-10)
binary: rustc
commit-hash: 90743e7298aca107ddaa0c202a4d3604e29bfeb6
commit-date: 2023-01-10
host: i686-pc-windows-msvc
release: 1.66.1
LLVM version: 15.0.2
rustc 1.68.0-nightly (1e4f90061 2023-01-11)
binary: rustc
commit-hash: 1e4f90061cc4bc566f99ab21b1f101182b10cf0c
commit-date: 2023-01-11
host: i686-pc-windows-msvc
release: 1.68.0-nightly
LLVM version: 15.0.6
No backtrace available.