llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29k stars 11.95k forks source link

[AArch64] Incorrect register used for inline assembly input #58384

Open Amanieu opened 2 years ago

Amanieu commented 2 years ago
define void @foo() {
  %1 = call i32 asm sideeffect "", "={x0},0"(i32 435)
  ret void
}

With llc -march=aarch64 -O0, this generates the following assembly.

foo:                                    // @foo
    .cfi_startproc
// %bb.0:
    mov w8, #435
    mrs x0, NZCV
    //APP
    //NO_APP
    ret

Using ={x0},{x0} instead of ={x0},0 seems to avoid this issue,

This IR is generated by rustc's inline assembly for an inout("x8") operand, so perhaps this is rustc's fault? Actually I can reproduce this bug in Clang as well, so it's definitely not an issue that is unique to rustc.

void foo() {
    register int x asm("x8") = 435;
    asm volatile("" : "+&r" (x));
}
nikic commented 2 years ago

Causes an assertion failure:

X0 = COPY W8
unimplemented reg-to-reg copy
llvmbot commented 2 years ago

@llvm/issue-subscribers-backend-aarch64

Amanieu commented 2 years ago

I worked around this in rustc (https://github.com/rust-lang/rust/pull/103897) by renaming the register to wN instead of xN if the type is 32-bit or smaller. Perhaps this should be solved in the frontend in Clang?