llvm / llvm/llvm-project

[m68k] Miscompilation: Move immediate to status register generates incorrect assembly

Open
#165,077 3 comments 0 reactions 0 assignees View on GitHub
backend:m68k miscompilation
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Initially ran into this error in Rust:
```rust
unsafe fn set_int_level() {
core::arch::asm!(
"move.w #{l},%sr",
l = const (0x2000i16 | (((LEVEL & 0x7) as i16) << 8)),
)
}
```
Tried a simpler case in C and compiled using clang:
https://godbolt.org/z/eMh7qWz6G
```c
/* Example usecase: Disabling interrupts by setting the interrupt mask bits of SR to 7. */
void disable_interrupts() {
asm("move.w #0x2700,%sr");
}
```
Both backends generated IR similar to this:
```ir
define dso_local void @disable_interrupts() {
entry:
call void asm sideeffect "move.w #0x2700,%sr", ""() #1
ret void
}
```
However, something goes wrong during codegen, and somehow the `move.w #imm,%sr` directive turns into `move.w #imm,%d0`:
```asm
disable_interrupts:
link.w %a6, #0
move.w #9984, %d0
unlk %a6
rts
```
The issue can technically be bypassed by moving the immediate value into a temporary register, and then into the status register, but it's still incorrect behavior by the codegen backend.

Contributor guide

Open the contributing guide

Research direction

Start with the Rust and C reproductions, then compare the LLVM IR containing the inline asm with the generated m68k assembly. Trace the codegen backend handling of `move.w #imm,%sr` and verify that the immediate remains targeted at `%sr` rather than becoming `%d0`; confirm the fix with both examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.