Skip to content

Inline assembly with tied operands of different sizes #65452

Description

@ahomescu

When transpiling (or manually translating) the following C code from /usr/include/bits/select.h:

# define __FD_ZERO(fdsp) \
  do {									      \
    int __d0, __d1;							      \
    __asm__ __volatile__ ("cld; rep; " __FD_ZERO_STOS			      \
			  : "=c" (__d0), "=D" (__d1)			      \
			  : "a" (0), "0" (sizeof (fd_set)		      \
					  / sizeof (__fd_mask)),	      \
			    "1" (&__FDS_BITS (fdsp)[0])			      \
			  : "memory");					      \
  } while (0)

into Rust, we get approximately the following code (manually rewritten to make it cleaner):

    let mut x: u32 = 0;
    let mut y: u32;
    let mut z: u32;
    unsafe {
        asm!("cld; rep stosb"
             : "={di}"(y), "={cx}"(z)
             : "{al}"(42), "0"(&mut x), "1"(4)
             : "memory"
             : "volatile"
             );
    }

the resulting Rust inline assembly works fine in release mode, but crashes in debug mode.
Link to Playground

The issue here is that the "0"(&mut x) input operand is tied to the same register as the "={di}"(y) output operand, but they have different types and sizes (&mut u32 vs u32). LLVM assigns both operands to the edi register in debug mode (which is wrong) but to rdi in release mode (which is the expected assignment).

gcc and clang compile the original C code correctly because they extend both operands to the larger size in the front end (link to clang code). The equivalent correct Rust code would be something like

    unsafe {
        let y64: u64;
        asm!("cld; rep stosb"
             : "={di}"(y64), "={cx}"(z)
             : "{al}"(42), "0"(&mut x), "1"(4)
             : "memory"
             : "volatile"
             );
        y = y64 as u32;
    }

Should rustc expect to never see this input (I think it's LLVM UB), or replicate clang's behavior? If it's the latter, I could implement that myself and submit a PR, but I'm trying to get some feedback before writing any code.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inline-assemblyArea: Inline assembly (`asm!(…)`)P-lowLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions