[llvm] [M68k] Fix Instruction Verifier errors related to `MOVEM` and `PHI` lowering (PR #219011)

Dan Salvato via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 11:57:03 PDT 2026


https://github.com/dansalvato updated https://github.com/llvm/llvm-project/pull/219011

>From fedcfd7f3cf09fcc7c6d300c6fca2eec309cd021 Mon Sep 17 00:00:00 2001
From: Dan Salvato <dan at teamsalvato.com>
Date: Wed, 26 Aug 2026 13:17:53 -0400
Subject: [PATCH 1/2] [M68k] Fix `MOVEM` and `PHI` Instruction Verifier errors

---
 .../lib/Target/M68k/M68kCollapseMOVEMPass.cpp | 25 ++++---
 llvm/lib/Target/M68k/M68kExpandPseudo.cpp     |  4 ++
 llvm/lib/Target/M68k/M68kInstrData.td         |  8 +++
 llvm/lib/Target/M68k/M68kInstrInfo.cpp        |  2 +-
 llvm/lib/Target/M68k/M68kRegisterInfo.td      |  2 +-
 llvm/test/CodeGen/M68k/Control/cmp-cse.ll     | 66 +++++++++++++++++++
 6 files changed, 95 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/CodeGen/M68k/Control/cmp-cse.ll

diff --git a/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp b/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
index 38770a95d2815..c9a3a4ba9ea69 100644
--- a/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
+++ b/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
@@ -182,26 +182,31 @@ class M68kCollapseMOVEM : public MachineFunctionPass {
       return;
     }
 
-    // Delete all the MOVEM instruction till the end
-    while (MI != End) {
-      auto Next = std::next(MI);
-      MBB.erase(MI);
-      MI = Next;
-    }
-
-    // Add a unified one
+    // Add a unified MOVEM
+    MachineInstrBuilder NewMIB;
     if (State.isLoad()) {
-      BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))
+      NewMIB = BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))
           .addImm(State.getMask())
           .addImm(State.getFinalOffset())
           .addReg(State.getBase());
     } else {
-      BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))
+      NewMIB = BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))
           .addImm(State.getFinalOffset())
           .addReg(State.getBase())
           .addImm(State.getMask());
     }
 
+    // Delete all the old MOVEM instructions, and copy their implicit defs/uses
+    // over to the new instruction.
+    MachineFunction *MF = MBB.getParent();
+    MachineInstr *NewMI = NewMIB.getInstr();
+    while (MI != NewMI) {
+      auto Next = std::next(MI);
+      NewMI->copyImplicitOps(*MF, *MI);
+      MBB.erase(MI);
+      MI = Next;
+    }
+
     State = MOVEMState();
   }
 
diff --git a/llvm/lib/Target/M68k/M68kExpandPseudo.cpp b/llvm/lib/Target/M68k/M68kExpandPseudo.cpp
index 7e73530461ec9..39e6eeb912a6e 100644
--- a/llvm/lib/Target/M68k/M68kExpandPseudo.cpp
+++ b/llvm/lib/Target/M68k/M68kExpandPseudo.cpp
@@ -187,21 +187,25 @@ bool M68kExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16dq), MVT::i32,
                                 MVT::i16);
 
+  case M68k::MOVM8jm_P:
   case M68k::MOVM16jm_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM16jm), /*IsRM=*/false);
   case M68k::MOVM32jm_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false);
 
+  case M68k::MOVM8pm_P:
   case M68k::MOVM16pm_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM16pm), /*IsRM=*/false);
   case M68k::MOVM32pm_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false);
 
+  case M68k::MOVM8mj_P:
   case M68k::MOVM16mj_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM16mj), /*IsRM=*/true);
   case M68k::MOVM32mj_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true);
 
+  case M68k::MOVM8mp_P:
   case M68k::MOVM16mp_P:
     return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM16mp), /*IsRM=*/true);
   case M68k::MOVM32mp_P:
diff --git a/llvm/lib/Target/M68k/M68kInstrData.td b/llvm/lib/Target/M68k/M68kInstrData.td
index a9f565f4c5ae9..293949235d2dd 100644
--- a/llvm/lib/Target/M68k/M68kInstrData.td
+++ b/llvm/lib/Target/M68k/M68kInstrData.td
@@ -369,17 +369,25 @@ let mayLoad = 1 in
 class MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp>
     : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>;
 
+// Note that MOVEM doesn't natively support 8-bit values; the pseudos for these
+// get expanded to MOVM16. But they keep the instruction verifier from reporting
+// a mismatch on physical registers.
+
 // Mem <- Reg
+def MOVM8jm_P : MxMOVEM_MR_Pseudo<MxType8d, MxType8.JOp>;
 def MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>;
 def MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>;
 
+def MOVM8pm_P : MxMOVEM_MR_Pseudo<MxType8d, MxType8.POp>;
 def MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>;
 def MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>;
 
 // Reg <- Mem
+def MOVM8mj_P : MxMOVEM_RM_Pseudo<MxType8d, MxType8.JOp>;
 def MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>;
 def MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>;
 
+def MOVM8mp_P : MxMOVEM_RM_Pseudo<MxType8d, MxType8.POp>;
 def MOVM16mp_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.POp>;
 def MOVM32mp_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.POp>;
 
diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.cpp b/llvm/lib/Target/M68k/M68kInstrInfo.cpp
index 975be36935f6d..b7d24a62f9d38 100644
--- a/llvm/lib/Target/M68k/M68kInstrInfo.cpp
+++ b/llvm/lib/Target/M68k/M68kInstrInfo.cpp
@@ -893,7 +893,7 @@ unsigned getLoadStoreRegOpcode(unsigned Reg, const TargetRegisterClass *RC,
     if (M68k::XR16RegClass.hasSubClassEq(RC))
       return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
     if (M68k::DR8RegClass.hasSubClassEq(RC))
-      return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
+      return load ? M68k::MOVM8mp_P : M68k::MOVM8pm_P;
     if (M68k::CCRCRegClass.hasSubClassEq(RC))
       return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
     llvm_unreachable("Unknown 2-byte regclass");
diff --git a/llvm/lib/Target/M68k/M68kRegisterInfo.td b/llvm/lib/Target/M68k/M68kRegisterInfo.td
index 25492c6fc9406..86493e331bd6f 100644
--- a/llvm/lib/Target/M68k/M68kRegisterInfo.td
+++ b/llvm/lib/Target/M68k/M68kRegisterInfo.td
@@ -133,7 +133,7 @@ def FPDR64 : MxRegClass<[f64], 32, (add FPDR32)>;
 let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<80,128,32>]> in
 def FPDR80 : MxRegClass<[f80], 32, (add FPDR32)>;
 
-let CopyCost = -1 in {
+let CopyCost = -1, isAllocatable = 0 in {
   let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<8,16,16>]> in
   def CCRC : MxRegClass<[i8],  16, (add CCR)>;
   let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
diff --git a/llvm/test/CodeGen/M68k/Control/cmp-cse.ll b/llvm/test/CodeGen/M68k/Control/cmp-cse.ll
new file mode 100644
index 0000000000000..c4aa64a257573
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/Control/cmp-cse.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=m68k-linux -verify-machineinstrs | FileCheck %s
+
+; The purpose of this test is to ensure that %cmp2 doesn't emit a redundant
+; compare instruction; it should be eliminated by CSE.
+define i1 @cse(ptr %y) nounwind {
+; CHECK-LABEL: cse:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    move.l (4,%sp), %a0
+; CHECK-NEXT:    move.w (%a0), %d0
+; CHECK-NEXT:    cmpi.w #0, %d0
+; CHECK-NEXT:    bmi .LBB0_2
+; CHECK-NEXT:  ; %bb.1: ; %cmp2
+; CHECK-NEXT:    beq .LBB0_3
+; CHECK-NEXT:  .LBB0_2: ; %yes
+; CHECK-NEXT:    moveq #1, %d0
+; CHECK-NEXT:    rts
+; CHECK-NEXT:  .LBB0_3: ; %no
+; CHECK-NEXT:    clr.b %d0
+; CHECK-NEXT:    rts
+  %1 = load i16, ptr %y
+  %2 = icmp slt i16 %1, 0
+  br i1 %2, label %yes, label %cmp2
+
+cmp2:
+  %.not = icmp eq i16 %1, 0
+  br i1 %.not, label %no, label %yes
+
+yes:
+  ret i1 1
+
+no:
+  ret i1 0
+}
+
+; The compare condition is different and therefore not eliminated by CSE.
+define i1 @no_cse(ptr %y) nounwind {
+; CHECK-LABEL: no_cse:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    move.l (4,%sp), %a0
+; CHECK-NEXT:    move.w (%a0), %d0
+; CHECK-NEXT:    cmpi.w #0, %d0
+; CHECK-NEXT:    bmi .LBB1_2
+; CHECK-NEXT:  ; %bb.1: ; %cmp2
+; CHECK-NEXT:    cmpi.w #10, %d0
+; CHECK-NEXT:    bne .LBB1_2
+; CHECK-NEXT:  ; %bb.3: ; %no
+; CHECK-NEXT:    clr.b %d0
+; CHECK-NEXT:    rts
+; CHECK-NEXT:  .LBB1_2: ; %yes
+; CHECK-NEXT:    moveq #1, %d0
+; CHECK-NEXT:    rts
+  %1 = load i16, ptr %y
+  %2 = icmp slt i16 %1, 0
+  br i1 %2, label %yes, label %cmp2
+
+cmp2:
+  %.not = icmp eq i16 %1, 10
+  br i1 %.not, label %no, label %yes
+
+yes:
+  ret i1 1
+
+no:
+  ret i1 0
+}

>From 050358df49109ec332320e03f72c8b34809d097a Mon Sep 17 00:00:00 2001
From: Dan Salvato <dan at teamsalvato.com>
Date: Wed, 26 Aug 2026 14:56:51 -0400
Subject: [PATCH 2/2] clang-format

---
 llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp b/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
index c9a3a4ba9ea69..286ea0aa74d7f 100644
--- a/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
+++ b/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
@@ -186,14 +186,14 @@ class M68kCollapseMOVEM : public MachineFunctionPass {
     MachineInstrBuilder NewMIB;
     if (State.isLoad()) {
       NewMIB = BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))
-          .addImm(State.getMask())
-          .addImm(State.getFinalOffset())
-          .addReg(State.getBase());
+                   .addImm(State.getMask())
+                   .addImm(State.getFinalOffset())
+                   .addReg(State.getBase());
     } else {
       NewMIB = BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))
-          .addImm(State.getFinalOffset())
-          .addReg(State.getBase())
-          .addImm(State.getMask());
+                   .addImm(State.getFinalOffset())
+                   .addReg(State.getBase())
+                   .addImm(State.getMask());
     }
 
     // Delete all the old MOVEM instructions, and copy their implicit defs/uses



More information about the llvm-commits mailing list