[M68k] CCR preservation mechanism needs a more performant and reliable permanent solution
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
This is a continuation of #152816. The issue was resolved in #168485, but with the intention of it being a temporary measure until a more permanent solution is devised.
## The core issue
LLVM's `COPY` pseudo-instruction (lowered via `copyPhysReg()`) expects the target architecture to be able to copy registers with no side effects. Unfortunately, m68k can't perfectly do this without affecting CCR (condition/status flags).
The current solution in place is that `copyPhysReg()` includes logic to check if the CCR is live, and if so, it backs up the CCR, then restores it after the register copy.
## Issues with the current solution
- It's very inefficient to back up and restore the CCR in this manner, especially when the machine code can usually be logically restructured to prevent it from being necessary in the first place.
- With this solution, binaries built for 68000 are incompatible with 68010+. The reason is that 68000 lacks "Move from/to CCR" instructions, so it must instead use "Move to/from SR", which requires supervisor mode on 68010+. This sacrifice feels unnecessary, because all mainline m68k CPUs were designed to be backwards-compatible with 68000 code.
## FAQ
### Why not tell LLVM that `COPY` kills the CCR?
The definition of the `COPY` pseudo-instruction is "Copy one physical register to another without any side effects". So, implementing the instruction in the first place means implementing it as defined.
### Why not adjust register liveness during `CopyPhysReg()` to tell LLVM it's killing a live register?
LLVM lowers `COPY` *after* physical register allocation, and in fact inserts the instruction when needed as part of the register allocation process. So, adjusting liveness properties during `copyPhysReg()` will have no effect, since LLVM is already done using that information to allocate registers.
### Does m68k really have no way to copy a register without affecting CCR?
There are technically two ways of doing it, but they have their own problems.
```m68k
movem.w d0,-(sp)
movem.w (sp)+,d1
```
```m68k
exg d1,a0
movea.w d0,a0
exg d1,a0
```
Both of these share the same problem: They can't copy a byte (only a word or a longword), and they get sign-extended to longword on copy.
Theoretically, that *might* not be a problem, since if LLVM is trying to copy a byte- or word-sized register, then it likely implies that the upper bytes of the destination register are currently dead anyway. But that makes assumptions on how both LLVM and the M68k backend logically make use of subregisters (whether now or in the future). It doesn't fix "no side effects"—it merely moves the side effects somewhere that's less likely to cause a miscompile.
Contributor guide
Research direction
Start with the M68k backend's copyPhysReg() implementation and the LLVM COPY pseudo-instruction definition, then review how CCR liveness is handled during register allocation. The work is complete when the backend has a permanent, performant CCR-preserving register-copy mechanism that remains compatible across 68000 and 68010+ targets without relying on the current workaround.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100