Skip to content

[M68k] always use movem for register spills #106715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions llvm/lib/Target/M68k/M68kExpandPseudo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,31 +193,23 @@ bool M68kExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
case M68k::MOV8dc:
return TII->ExpandCCR(MIB, /*IsToCCR=*/false);

case M68k::MOVM8jm_P:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false);
case M68k::MOVM16jm_P:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false);
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:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false);
case M68k::MOVM16pm_P:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false);
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:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true);
case M68k::MOVM16mj_P:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true);
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:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true);
case M68k::MOVM16mp_P:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true);
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM16mp), /*IsRM=*/true);
case M68k::MOVM32mp_P:
return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true);

Expand Down
4 changes: 0 additions & 4 deletions llvm/lib/Target/M68k/M68kInstrData.td
Original file line number Diff line number Diff line change
Expand Up @@ -337,20 +337,16 @@ class MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp>
: MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>;

// 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>;

Expand Down
35 changes: 15 additions & 20 deletions llvm/lib/Target/M68k/M68kInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,6 @@ bool M68kInstrInfo::ExpandCCR(MachineInstrBuilder &MIB, bool IsToCCR) const {
bool M68kInstrInfo::ExpandMOVEM(MachineInstrBuilder &MIB,
const MCInstrDesc &Desc, bool IsRM) const {
int Reg = 0, Offset = 0, Base = 0;
auto XR32 = RI.getRegClass(M68k::XR32RegClassID);
auto DL = MIB->getDebugLoc();
auto MI = MIB.getInstr();
auto &MBB = *MIB->getParent();
Expand All @@ -608,13 +607,6 @@ bool M68kInstrInfo::ExpandMOVEM(MachineInstrBuilder &MIB,
Reg = MIB->getOperand(2).getReg();
}

// If the register is not in XR32 then it is smaller than 32 bit, we
// implicitly promote it to 32
if (!XR32->contains(Reg)) {
Reg = RI.getMatchingMegaReg(Reg, XR32);
assert(Reg && "Has not meaningful MEGA register");
}

unsigned Mask = 1 << RI.getSpillRegisterOrder(Reg);
if (IsRM) {
BuildMI(MBB, MI, DL, Desc)
Expand Down Expand Up @@ -799,22 +791,25 @@ namespace {
unsigned getLoadStoreRegOpcode(unsigned Reg, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI,
const M68kSubtarget &STI, bool load) {
switch (TRI->getRegSizeInBits(*RC)) {
switch (TRI->getSpillSize(*RC)) {
default:
LLVM_DEBUG(
dbgs() << "Cannot determine appropriate opcode for load/store to/from "
<< TRI->getName(Reg) << " of class " << TRI->getRegClassName(RC)
<< " with spill size " << TRI->getSpillSize(*RC) << '\n');
llvm_unreachable("Unknown spill size");
case 8:
case 2:
if (M68k::XR16RegClass.hasSubClassEq(RC))
return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
if (M68k::DR8RegClass.hasSubClassEq(RC))
return load ? M68k::MOV8dp : M68k::MOV8pd;
return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
if (M68k::CCRCRegClass.hasSubClassEq(RC))
return load ? M68k::MOV16cp : M68k::MOV16pc;

llvm_unreachable("Unknown 1-byte regclass");
case 16:
assert(M68k::XR16RegClass.hasSubClassEq(RC) && "Unknown 2-byte regclass");
return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
case 32:
assert(M68k::XR32RegClass.hasSubClassEq(RC) && "Unknown 4-byte regclass");
return load ? M68k::MOVM32mp_P : M68k::MOVM32pm_P;
return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P;
llvm_unreachable("Unknown 2-byte regclass");
case 4:
if (M68k::XR32RegClass.hasSubClassEq(RC))
return load ? M68k::MOVM32mp_P : M68k::MOVM32pm_P;
llvm_unreachable("Unknown 4-byte regclass");
}
}

Expand Down
35 changes: 30 additions & 5 deletions llvm/lib/Target/M68k/M68kRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -99,52 +99,77 @@ class MxRegClass<list<ValueType> regTypes, int alignment, dag regList>
: RegisterClass<"M68k", regTypes, alignment, regList>;

// Data Registers
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<8,16,16>]> in
def DR8 : MxRegClass<[i8], 16, (sequence "BD%u", 0, 7)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def DR16 : MxRegClass<[i16], 16, (sequence "WD%u", 0, 7)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def DR32 : MxRegClass<[i32], 32, (sequence "D%u", 0, 7)>;

// Address Registers
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def AR16 : MxRegClass<[i16], 16, (add (sequence "WA%u", 0, 6), WSP)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def AR32 : MxRegClass<[i32], 32, (add (sequence "A%u", 0, 6), SP)>;

let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def AR32_NOSP : MxRegClass<[i32], 32, (sequence "A%u", 0, 6)>;

// Index Register Classes
// FIXME try alternative ordering like `D0, D1, A0, A1, ...`
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def XR16 : MxRegClass<[i16], 16, (add DR16, AR16)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def XR32 : MxRegClass<[i32], 32, (add DR32, AR32)>;

let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def SPC : MxRegClass<[i32], 32, (add SP)>;

// Floating Point Data Registers
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def FPDR32 : MxRegClass<[f32], 32, (sequence "FP%u", 0, 7)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<64,64,32>]> in
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 RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<8,16,16>]> in
def CCRC : MxRegClass<[i8], 16, (add CCR)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def SRC : MxRegClass<[i16], 16, (add SR)>;

// Float Point System Control Registers
def FPIC : MxRegClass<[i32], 32, (add FPIAR)>;
def FPCSC : MxRegClass<[i32], 32, (add FPC, FPS)>;
def FPSYSC : MxRegClass<[i32], 32, (add FPCSC, FPIC)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in {
def FPIC : MxRegClass<[i32], 32, (add FPIAR)>;
def FPCSC : MxRegClass<[i32], 32, (add FPC, FPS)>;
def FPSYSC : MxRegClass<[i32], 32, (add FPCSC, FPIC)>;
}
}

let isAllocatable = 0 in {
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def PCC : MxRegClass<[i32], 32, (add PC)>;
}

// Register used with tail call
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def DR16_TC : MxRegClass<[i16], 16, (add D0, D1)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def DR32_TC : MxRegClass<[i32], 32, (add D0, D1)>;

let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def AR16_TC : MxRegClass<[i16], 16, (add A0, A1)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def AR32_TC : MxRegClass<[i32], 32, (add A0, A1)>;

let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<16,16,16>]> in
def XR16_TC : MxRegClass<[i16], 16, (add DR16_TC, AR16_TC)>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in
def XR32_TC : MxRegClass<[i32], 32, (add DR32_TC, AR32_TC)>;

// These classes provide spill/restore order if used with MOVEM instruction
def SPILL : MxRegClass<[i32], 32, (add XR32)>;
def SPILL_R : MxRegClass<[i32], 32, (add SP, (sequence "A%u", 6, 0), (sequence "D%u", 7, 0))>;
let RegInfos = RegInfoByHwMode<[DefaultMode], [RegInfo<32,32,32>]> in {
def SPILL : MxRegClass<[i32], 32, (add XR32)>;
def SPILL_R : MxRegClass<[i32], 32, (add SP, (sequence "A%u", 6, 0), (sequence "D%u", 7, 0))>;
}
22 changes: 11 additions & 11 deletions llvm/test/CodeGen/M68k/PR57660.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ define dso_local void @foo1() {
; CHECK-NEXT: suba.l #2, %sp
; CHECK-NEXT: .cfi_def_cfa_offset -6
; CHECK-NEXT: moveq #0, %d0
; CHECK-NEXT: move.b %d0, (0,%sp) ; 1-byte Folded Spill
; CHECK-NEXT: movem.w %d0, (0,%sp)
; CHECK-NEXT: .LBB0_1: ; %do.body
; CHECK-NEXT: ; =>This Inner Loop Header: Depth=1
; CHECK-NEXT: move.b (0,%sp), %d0 ; 1-byte Folded Reload
; CHECK-NEXT: movem.w (0,%sp), %d0
; CHECK-NEXT: cmpi.b #0, %d0
; CHECK-NEXT: bne .LBB0_1
; CHECK-NEXT: ; %bb.2: ; %do.end
Expand Down Expand Up @@ -39,24 +39,24 @@ define i32 @foo2(ptr noundef %0) {
; CHECK-NEXT: .cfi_def_cfa_offset -8
; CHECK-NEXT: move.l (8,%sp), %a0
; CHECK-NEXT: move.b (%a0), %d0
; CHECK-NEXT: move.b %d0, (0,%sp) ; 1-byte Folded Spill
; CHECK-NEXT: movem.w %d0, (0,%sp)
; CHECK-NEXT: and.b #1, %d0
; CHECK-NEXT: move.b %d0, (2,%sp) ; 1-byte Folded Spill
; CHECK-NEXT: movem.w %d0, (2,%sp)
; CHECK-NEXT: sub.b #1, %d0
; CHECK-NEXT: bgt .LBB1_2
; CHECK-NEXT: ; %bb.1: ; %if
; CHECK-NEXT: move.b (2,%sp), %d0 ; 1-byte Folded Reload
; CHECK-NEXT: move.b (0,%sp), %d1 ; 1-byte Folded Reload
; CHECK-NEXT: movem.w (2,%sp), %d0
; CHECK-NEXT: movem.w (0,%sp), %d1
; CHECK-NEXT: add.b %d1, %d0
; CHECK-NEXT: bra .LBB1_3
; CHECK-NEXT: .LBB1_2: ; %else
; CHECK-NEXT: move.b (2,%sp), %d1 ; 1-byte Folded Reload
; CHECK-NEXT: move.b (0,%sp), %d0 ; 1-byte Folded Reload
; CHECK-NEXT: movem.w (2,%sp), %d1
; CHECK-NEXT: movem.w (0,%sp), %d0
; CHECK-NEXT: sub.b %d1, %d0
; CHECK-NEXT: move.b %d0, (0,%sp) ; 1-byte Folded Spill
; CHECK-NEXT: movem.w %d0, (0,%sp)
; CHECK-NEXT: .LBB1_3: ; %cont
; CHECK-NEXT: move.b %d0, (2,%sp) ; 1-byte Folded Spill
; CHECK-NEXT: move.b (2,%sp), %d0 ; 1-byte Folded Reload
; CHECK-NEXT: movem.w %d0, (2,%sp)
; CHECK-NEXT: movem.w (2,%sp), %d0
; CHECK-NEXT: ext.w %d0
; CHECK-NEXT: ext.l %d0
; CHECK-NEXT: adda.l #4, %sp
Expand Down
Loading