1 //===-- M68kExpandPseudo.cpp - Expand pseudo instructions -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file contains a pass that expands pseudo instructions into target 11 /// instructions to allow proper scheduling, if-conversion, other late 12 /// optimizations, or simply the encoding of the instructions. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "M68k.h" 17 #include "M68kFrameLowering.h" 18 #include "M68kInstrInfo.h" 19 #include "M68kMachineFunction.h" 20 #include "M68kSubtarget.h" 21 22 #include "llvm/Analysis/EHPersonalities.h" 23 #include "llvm/CodeGen/MachineFunctionPass.h" 24 #include "llvm/CodeGen/MachineInstrBuilder.h" 25 #include "llvm/CodeGen/MachineRegisterInfo.h" 26 #include "llvm/CodeGen/Passes.h" // For IDs of passes that are preserved. 27 #include "llvm/IR/GlobalValue.h" 28 29 using namespace llvm; 30 31 #define DEBUG_TYPE "M68k-expand-pseudos" 32 33 namespace { 34 class M68kExpandPseudo : public MachineFunctionPass { 35 public: 36 static char ID; 37 M68kExpandPseudo() : MachineFunctionPass(ID) {} 38 39 void getAnalysisUsage(AnalysisUsage &AU) const override { 40 AU.setPreservesCFG(); 41 AU.addPreservedID(MachineLoopInfoID); 42 AU.addPreservedID(MachineDominatorsID); 43 MachineFunctionPass::getAnalysisUsage(AU); 44 } 45 46 const M68kSubtarget *STI; 47 const M68kInstrInfo *TII; 48 const M68kRegisterInfo *TRI; 49 const M68kMachineFunctionInfo *MFI; 50 const M68kFrameLowering *FL; 51 52 bool runOnMachineFunction(MachineFunction &Fn) override; 53 54 MachineFunctionProperties getRequiredProperties() const override { 55 return MachineFunctionProperties().set( 56 MachineFunctionProperties::Property::NoVRegs); 57 } 58 59 StringRef getPassName() const override { 60 return "M68k pseudo instruction expansion pass"; 61 } 62 63 private: 64 bool ExpandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); 65 bool ExpandMBB(MachineBasicBlock &MBB); 66 }; 67 char M68kExpandPseudo::ID = 0; 68 } // End anonymous namespace. 69 70 /// If \p MBBI is a pseudo instruction, this method expands 71 /// it to the corresponding (sequence of) actual instruction(s). 72 /// \returns true if \p MBBI has been expanded. 73 bool M68kExpandPseudo::ExpandMI(MachineBasicBlock &MBB, 74 MachineBasicBlock::iterator MBBI) { 75 MachineInstr &MI = *MBBI; 76 MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI); 77 unsigned Opcode = MI.getOpcode(); 78 DebugLoc DL = MBBI->getDebugLoc(); 79 /// TODO infer argument size to create less switch cases 80 switch (Opcode) { 81 default: 82 return false; 83 84 case M68k::MOVXd16d8: 85 return TII->ExpandMOVX_RR(MIB, MVT::i16, MVT::i8); 86 case M68k::MOVXd32d8: 87 return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i8); 88 case M68k::MOVXd32d16: 89 return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i16); 90 91 case M68k::MOVSXd16d8: 92 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i16, MVT::i8); 93 case M68k::MOVSXd32d8: 94 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i32, MVT::i8); 95 case M68k::MOVSXd32d16: 96 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i32, MVT::i16); 97 98 case M68k::MOVZXd16d8: 99 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i16, MVT::i8); 100 case M68k::MOVZXd32d8: 101 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i32, MVT::i8); 102 case M68k::MOVZXd32d16: 103 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i32, MVT::i16); 104 105 case M68k::MOVSXd16j8: 106 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i16, 107 MVT::i8); 108 case M68k::MOVSXd32j8: 109 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i32, 110 MVT::i8); 111 case M68k::MOVSXd32j16: 112 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rj), MVT::i32, 113 MVT::i16); 114 115 case M68k::MOVZXd16j8: 116 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i16, 117 MVT::i8); 118 case M68k::MOVZXd32j8: 119 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i32, 120 MVT::i8); 121 case M68k::MOVZXd32j16: 122 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rj), MVT::i32, 123 MVT::i16); 124 125 case M68k::MOVSXd16p8: 126 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i16, 127 MVT::i8); 128 case M68k::MOVSXd32p8: 129 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i32, 130 MVT::i8); 131 case M68k::MOVSXd32p16: 132 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rp), MVT::i32, 133 MVT::i16); 134 135 case M68k::MOVZXd16p8: 136 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i16, 137 MVT::i8); 138 case M68k::MOVZXd32p8: 139 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i32, 140 MVT::i8); 141 case M68k::MOVZXd32p16: 142 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rp), MVT::i32, 143 MVT::i16); 144 145 case M68k::MOVSXd16f8: 146 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i16, 147 MVT::i8); 148 case M68k::MOVSXd32f8: 149 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i32, 150 MVT::i8); 151 case M68k::MOVSXd32f16: 152 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rf), MVT::i32, 153 MVT::i16); 154 155 case M68k::MOVZXd16f8: 156 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i16, 157 MVT::i8); 158 case M68k::MOVZXd32f8: 159 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i32, 160 MVT::i8); 161 case M68k::MOVZXd32f16: 162 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rf), MVT::i32, 163 MVT::i16); 164 165 case M68k::MOV8cd: 166 return TII->ExpandCCR(MIB, /*IsToCCR=*/true); 167 case M68k::MOV8dc: 168 return TII->ExpandCCR(MIB, /*IsToCCR=*/false); 169 170 case M68k::MOVM8jm_P: 171 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 172 case M68k::MOVM16jm_P: 173 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 174 case M68k::MOVM32jm_P: 175 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 176 177 case M68k::MOVM8pm_P: 178 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 179 case M68k::MOVM16pm_P: 180 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 181 case M68k::MOVM32pm_P: 182 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 183 184 case M68k::MOVM8mj_P: 185 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 186 case M68k::MOVM16mj_P: 187 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 188 case M68k::MOVM32mj_P: 189 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 190 191 case M68k::MOVM8mp_P: 192 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 193 case M68k::MOVM16mp_P: 194 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 195 case M68k::MOVM32mp_P: 196 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 197 198 case M68k::TCRETURNq: 199 case M68k::TCRETURNj: { 200 MachineOperand &JumpTarget = MI.getOperand(0); 201 MachineOperand &StackAdjust = MI.getOperand(1); 202 assert(StackAdjust.isImm() && "Expecting immediate value."); 203 204 // Adjust stack pointer. 205 int StackAdj = StackAdjust.getImm(); 206 int MaxTCDelta = MFI->getTCReturnAddrDelta(); 207 int Offset = 0; 208 assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive"); 209 210 // Incoporate the retaddr area. 211 Offset = StackAdj - MaxTCDelta; 212 assert(Offset >= 0 && "Offset should never be negative"); 213 214 if (Offset) { 215 // Check for possible merge with preceding ADD instruction. 216 Offset += FL->mergeSPUpdates(MBB, MBBI, true); 217 FL->emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true); 218 } 219 220 // Jump to label or value in register. 221 if (Opcode == M68k::TCRETURNq) { 222 MachineInstrBuilder MIB = 223 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPq)); 224 if (JumpTarget.isGlobal()) { 225 MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), 226 JumpTarget.getTargetFlags()); 227 } else { 228 assert(JumpTarget.isSymbol()); 229 MIB.addExternalSymbol(JumpTarget.getSymbolName(), 230 JumpTarget.getTargetFlags()); 231 } 232 } else { 233 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPj)) 234 .addReg(JumpTarget.getReg(), RegState::Kill); 235 } 236 237 MachineInstr &NewMI = *std::prev(MBBI); 238 NewMI.copyImplicitOps(*MBBI->getParent()->getParent(), *MBBI); 239 240 // Delete the pseudo instruction TCRETURN. 241 MBB.erase(MBBI); 242 243 return true; 244 } 245 case M68k::RET: { 246 // Adjust stack to erase error code 247 int64_t StackAdj = MBBI->getOperand(0).getImm(); 248 MachineInstrBuilder MIB; 249 250 if (StackAdj == 0) { 251 MIB = BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); 252 } else if (isUInt<16>(StackAdj)) { 253 254 if (STI->atLeastM68020()) { 255 llvm_unreachable("RTD is not implemented"); 256 } else { 257 // Copy PC from stack to a free address(A0 or A1) register 258 // TODO check if pseudo expand uses free address register 259 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1) 260 .addReg(M68k::SP); 261 262 // Adjust SP 263 FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true); 264 265 // Put the return address on stack 266 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja)) 267 .addReg(M68k::SP) 268 .addReg(M68k::A1); 269 270 // RTS 271 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); 272 } 273 } else { 274 // TODO: RTD can only handle immediates as big as 2**16-1. 275 // If we need to pop off bytes before the return address, we 276 // must do it manually. 277 llvm_unreachable("Stack adjustment size not supported"); 278 } 279 280 // FIXME: Can rest of the operands be ignored, if there is any? 281 MBB.erase(MBBI); 282 return true; 283 } 284 } 285 llvm_unreachable("Previous switch has a fallthrough?"); 286 } 287 288 /// Expand all pseudo instructions contained in \p MBB. 289 /// \returns true if any expansion occurred for \p MBB. 290 bool M68kExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { 291 bool Modified = false; 292 293 // MBBI may be invalidated by the expansion. 294 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 295 while (MBBI != E) { 296 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 297 Modified |= ExpandMI(MBB, MBBI); 298 MBBI = NMBBI; 299 } 300 301 return Modified; 302 } 303 304 bool M68kExpandPseudo::runOnMachineFunction(MachineFunction &MF) { 305 STI = &static_cast<const M68kSubtarget &>(MF.getSubtarget()); 306 TII = STI->getInstrInfo(); 307 TRI = STI->getRegisterInfo(); 308 MFI = MF.getInfo<M68kMachineFunctionInfo>(); 309 FL = STI->getFrameLowering(); 310 311 bool Modified = false; 312 for (MachineBasicBlock &MBB : MF) 313 Modified |= ExpandMBB(MBB); 314 return Modified; 315 } 316 317 /// Returns an instance of the pseudo instruction expansion pass. 318 FunctionPass *llvm::createM68kExpandPseudoPass() { 319 return new M68kExpandPseudo(); 320 } 321