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