[m68k] Miscompilation: Move immediate to status register generates incorrect assembly
- 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
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