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::MOVSXd16q8: 165 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i16, 166 MVT::i8); 167 case M68k::MOVSXd32q8: 168 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i32, 169 MVT::i8); 170 case M68k::MOVSXd32q16: 171 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16dq), MVT::i32, 172 MVT::i16); 173 174 case M68k::MOVZXd16q8: 175 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i16, 176 MVT::i8); 177 case M68k::MOVZXd32q8: 178 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i32, 179 MVT::i8); 180 case M68k::MOVZXd32q16: 181 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16dq), MVT::i32, 182 MVT::i16); 183 184 case M68k::MOV8cd: 185 return TII->ExpandCCR(MIB, /*IsToCCR=*/true); 186 case M68k::MOV8dc: 187 return TII->ExpandCCR(MIB, /*IsToCCR=*/false); 188 189 case M68k::MOVM8jm_P: 190 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 191 case M68k::MOVM16jm_P: 192 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 193 case M68k::MOVM32jm_P: 194 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 195 196 case M68k::MOVM8pm_P: 197 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 198 case M68k::MOVM16pm_P: 199 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 200 case M68k::MOVM32pm_P: 201 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 202 203 case M68k::MOVM8mj_P: 204 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 205 case M68k::MOVM16mj_P: 206 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 207 case M68k::MOVM32mj_P: 208 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 209 210 case M68k::MOVM8mp_P: 211 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 212 case M68k::MOVM16mp_P: 213 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 214 case M68k::MOVM32mp_P: 215 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 216 217 case M68k::TCRETURNq: 218 case M68k::TCRETURNj: { 219 MachineOperand &JumpTarget = MI.getOperand(0); 220 MachineOperand &StackAdjust = MI.getOperand(1); 221 assert(StackAdjust.isImm() && "Expecting immediate value."); 222 223 // Adjust stack pointer. 224 int StackAdj = StackAdjust.getImm(); 225 int MaxTCDelta = MFI->getTCReturnAddrDelta(); 226 int Offset = 0; 227 assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive"); 228 229 // Incoporate the retaddr area. 230 Offset = StackAdj - MaxTCDelta; 231 assert(Offset >= 0 && "Offset should never be negative"); 232 233 if (Offset) { 234 // Check for possible merge with preceding ADD instruction. 235 Offset += FL->mergeSPUpdates(MBB, MBBI, true); 236 FL->emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true); 237 } 238 239 // Jump to label or value in register. 240 if (Opcode == M68k::TCRETURNq) { 241 MachineInstrBuilder MIB = 242 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPq)); 243 if (JumpTarget.isGlobal()) { 244 MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), 245 JumpTarget.getTargetFlags()); 246 } else { 247 assert(JumpTarget.isSymbol()); 248 MIB.addExternalSymbol(JumpTarget.getSymbolName(), 249 JumpTarget.getTargetFlags()); 250 } 251 } else { 252 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPj)) 253 .addReg(JumpTarget.getReg(), RegState::Kill); 254 } 255 256 MachineInstr &NewMI = *std::prev(MBBI); 257 NewMI.copyImplicitOps(*MBBI->getParent()->getParent(), *MBBI); 258 259 // Delete the pseudo instruction TCRETURN. 260 MBB.erase(MBBI); 261 262 return true; 263 } 264 case M68k::RET: { 265 if (MBB.getParent()->getFunction().getCallingConv() == 266 CallingConv::M68k_INTR) { 267 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTE)); 268 } else if (int64_t StackAdj = MBBI->getOperand(0).getImm(); StackAdj == 0) { 269 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); 270 } else { 271 // Copy return address from stack to a free address(A0 or A1) register 272 // TODO check if pseudo expand uses free address register 273 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1) 274 .addReg(M68k::SP); 275 276 // Adjust SP 277 FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true); 278 279 // Put the return address on stack 280 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja)) 281 .addReg(M68k::SP) 282 .addReg(M68k::A1); 283 284 // RTS 285 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); 286 } 287 288 // FIXME: Can rest of the operands be ignored, if there is any? 289 MBB.erase(MBBI); 290 return true; 291 } 292 } 293 llvm_unreachable("Previous switch has a fallthrough?"); 294 } 295 296 /// Expand all pseudo instructions contained in \p MBB. 297 /// \returns true if any expansion occurred for \p MBB. 298 bool M68kExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { 299 bool Modified = false; 300 301 // MBBI may be invalidated by the expansion. 302 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 303 while (MBBI != E) { 304 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 305 Modified |= ExpandMI(MBB, MBBI); 306 MBBI = NMBBI; 307 } 308 309 return Modified; 310 } 311 312 bool M68kExpandPseudo::runOnMachineFunction(MachineFunction &MF) { 313 STI = &MF.getSubtarget<M68kSubtarget>(); 314 TII = STI->getInstrInfo(); 315 TRI = STI->getRegisterInfo(); 316 MFI = MF.getInfo<M68kMachineFunctionInfo>(); 317 FL = STI->getFrameLowering(); 318 319 bool Modified = false; 320 for (MachineBasicBlock &MBB : MF) 321 Modified |= ExpandMBB(MBB); 322 return Modified; 323 } 324 325 /// Returns an instance of the pseudo instruction expansion pass. 326 FunctionPass *llvm::createM68kExpandPseudoPass() { 327 return new M68kExpandPseudo(); 328 } 329