[llvm] [M68k] Prevent COPY instruction from killing live condition flags (PR #168485)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 4 06:49:13 PDT 2026
================
@@ -690,86 +690,142 @@ void M68kInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
const DebugLoc &DL, Register DstReg,
Register SrcReg, bool KillSrc,
bool RenamableDest, bool RenamableSrc) const {
- const auto &Subtarget = MBB.getParent()->getSubtarget<M68kSubtarget>();
unsigned Opc = 0;
+ MachineFunction &MF = *MBB.getParent();
+ const M68kSubtarget &STI = MF.getSubtarget<M68kSubtarget>();
- // First deal with the normal symmetric copies.
- if (M68k::XR32RegClass.contains(DstReg, SrcReg))
+ // Symmetric register copies
+ if (M68k::XR32RegClass.contains(DstReg, SrcReg)) {
Opc = M68k::MOV32rr;
- else if (M68k::XR16RegClass.contains(DstReg, SrcReg))
+ } else if (M68k::XR16RegClass.contains(DstReg, SrcReg)) {
Opc = M68k::MOV16rr;
- else if (M68k::DR8RegClass.contains(DstReg, SrcReg))
+ } else if (M68k::DR8RegClass.contains(DstReg, SrcReg)) {
Opc = M68k::MOV8dd;
-
- if (Opc) {
- BuildMI(MBB, MI, DL, get(Opc), DstReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
- return;
}
- // Now deal with asymmetrically sized copies. The cases that follow are upcast
- // moves.
- //
- // NOTE
- // These moves are not aware of type nature of these values and thus
- // won't do any SExt or ZExt and upper bits will basically contain garbage.
- MachineInstrBuilder MIB(*MBB.getParent(), MI);
- if (M68k::DR8RegClass.contains(SrcReg)) {
- if (M68k::XR16RegClass.contains(DstReg))
- Opc = M68k::MOVXd16d8;
- else if (M68k::XR32RegClass.contains(DstReg))
- Opc = M68k::MOVXd32d8;
+ // Asymmetric register copies
+ // NOTE: There is no implicit sext/zext occurring during these moves, so the
+ // upper bits will be undefined.
+ // 8 -> 16
+ else if (M68k::DR8RegClass.contains(SrcReg) &&
+ M68k::XR16RegClass.contains(DstReg)) {
+ Opc = M68k::MOVXd16d8;
+ // 8 -> 32
+ } else if (M68k::DR8RegClass.contains(SrcReg) &&
+ M68k::XR32RegClass.contains(DstReg)) {
+ Opc = M68k::MOVXd32d8;
+ // 16 -> 32
} else if (M68k::XR16RegClass.contains(SrcReg) &&
- M68k::XR32RegClass.contains(DstReg))
+ M68k::XR32RegClass.contains(DstReg)) {
Opc = M68k::MOVXd32d16;
-
- if (Opc) {
- BuildMI(MBB, MI, DL, get(Opc), DstReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
- return;
}
- bool FromCCR = SrcReg == M68k::CCR;
- bool FromSR = SrcReg == M68k::SR;
- bool ToCCR = DstReg == M68k::CCR;
- bool ToSR = DstReg == M68k::SR;
-
- if (FromCCR) {
- Opc = M68k::MOV16dc;
- if (!Subtarget.atLeastM68010()) {
- Opc = M68k::MOV16ds;
- SrcReg = M68k::SR;
- }
- if (!M68k::DR8RegClass.contains(DstReg) &&
- !M68k::DR16RegClass.contains(DstReg) &&
- !M68k::DR32RegClass.contains(DstReg)) {
+ // Copy from CCR
+ // NOTE: M68000 uses MOVE from SR to copy from CCR, all other variants use
+ // MOVE from CCR.
+ else if (SrcReg == M68k::CCR) {
+ if (M68k::DR8RegClass.contains(DstReg) ||
+ M68k::DR16RegClass.contains(DstReg) ||
+ M68k::DR32RegClass.contains(DstReg)) {
+ Opc = STI.isM68000() ? M68k::MOV16ds : M68k::MOV16dc;
+ } else {
LLVM_DEBUG(dbgs() << "Cannot copy CCR to " << RI.getName(DstReg) << '\n');
llvm_unreachable("Invalid register for MOVE from CCR");
}
- } else if (ToCCR) {
- Opc = M68k::MOV16cd;
- if (M68k::DR8RegClass.contains(SrcReg)) {
- // Promote used register to the next class
- SrcReg = getRegisterInfo().getMatchingSuperReg(
- SrcReg, M68k::MxSubRegIndex8Lo, &M68k::DR16RegClass);
- } else if (!M68k::DR16RegClass.contains(SrcReg) &&
- !M68k::DR32RegClass.contains(SrcReg)) {
+ }
+
+ // Copy to CCR
+ else if (DstReg == M68k::CCR) {
+ if (M68k::DR8RegClass.contains(SrcReg) ||
+ M68k::DR16RegClass.contains(SrcReg) ||
+ M68k::DR32RegClass.contains(SrcReg)) {
+ Opc = M68k::MOV16cd;
+ } else {
LLVM_DEBUG(dbgs() << "Cannot copy " << RI.getName(SrcReg) << " to CCR\n");
llvm_unreachable("Invalid register for MOVE to CCR");
}
- } else if (FromSR || ToSR) {
- llvm_unreachable("Cannot emit SR copy instruction");
}
- if (Opc) {
+ // SR should never be a valid register for copying
+ else if (SrcReg == M68k::SR || DstReg == M68k::SR)
+ llvm_unreachable("Cannot explicitly copy to/from SR");
+
+ // We should now have our opcode
+ if (!Opc) {
+ LLVM_DEBUG(dbgs() << "Cannot copy " << RI.getName(SrcReg) << " to "
+ << RI.getName(DstReg) << '\n');
+ llvm_unreachable("Cannot emit physreg copy instruction");
+ }
+
+ // FIXME
+ // Below is a workaround to prevent a live CCR from being killed by the COPY
+ // instruction. LLVM sometimes inserts a COPY pseudo instruction between
+ // compare and branch during MIR generation (e.g. during PHI node elimination)
+ // without any idea that on M68k, this is extremely likely to implicitly kill
+ // the CCR.
+ // The workaround checks whether CCR is live during this copy, and if so,
+ // backs up CCR and restores it after the copy. It's inefficient and prevents
+ // M68000-targeted builds from running on 010+ (because 000 uses MOVE from SR
+ // and 010+ uses MOVE from CCR).
+ // The fix condition is to prevent COPY from ever being inserted while CCR is
+ // live (which would also stop this workaround from ever triggering).
+
+ unsigned CCRSrcReg = STI.isM68000() ? M68k::SR : M68k::CCR;
+
+ // Get the live registers right before the COPY instruction. If CCR is
+ // live, the MOVE is going to kill it, so we will need to preserve it.
+ LiveRegUnits UsedRegs(RI);
+ UsedRegs.addLiveOuts(MBB);
+ auto InstUpToI = MBB.end();
+ while (InstUpToI != MI) {
+ UsedRegs.stepBackward(*--InstUpToI);
+ }
+
+ if (SrcReg == M68k::CCR) {
+ BuildMI(MBB, MI, DL, get(Opc), DstReg).addReg(CCRSrcReg);
+ return;
+ }
+ if (DstReg == M68k::CCR) {
+ BuildMI(MBB, MI, DL, get(Opc), M68k::CCR)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ return;
+ }
+ if (UsedRegs.available(M68k::CCR)) {
BuildMI(MBB, MI, DL, get(Opc), DstReg)
.addReg(SrcReg, getKillRegState(KillSrc));
return;
}
- LLVM_DEBUG(dbgs() << "Cannot copy " << RI.getName(SrcReg) << " to "
- << RI.getName(DstReg) << '\n');
- llvm_unreachable("Cannot emit physreg copy instruction");
+ // CCR is live, so we must restore it after the copy. Prepare push/pop ops.
+ // 68000 must use MOVE from SR, 68010+ must use MOVE from CCR. In either
+ // case, upon moving back, MOVE to CCR will mask out the upper byte anyway.
+
+ // Look for an available data register for the CCR, or push to stack if
+ // there are none
+ BitVector Allocatable =
+ RI.getAllocatableSet(MF, RI.getRegClass(M68k::DR16RegClassID));
+ for (Register Reg : Allocatable.set_bits()) {
+ if (!RI.regsOverlap(DstReg, Reg) && (UsedRegs.available(Reg))) {
----------------
knickish wrote:
Do we need to check for overlap with Src here, or is that already excluded by `UsedRegs.available(Reg)`?
https://github.com/llvm/llvm-project/pull/168485
More information about the llvm-commits
mailing list