Skip to content

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

@SpacePython12

Description

@SpacePython12

Initially ran into this error in Rust:

unsafe fn set_int_level<const LEVEL: u8>() {
    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

/* 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:

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:

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions