Skip to content

Inline assembly fails to compile after allowing inlining on the enclosing function for i686-pc-windows-msvc #106781

Open
@johnmave126

Description

@johnmave126

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_endproc

However, 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inline-assemblyArea: Inline assembly (`asm!(…)`)C-bugCategory: This is a bug.O-x86_32Target: x86 processors, 32 bit (like i686-*) (IA-32)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions