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::MOVI8di: 84 return TII->ExpandMOVI(MIB, MVT::i8); 85 case M68k::MOVI16ri: 86 return TII->ExpandMOVI(MIB, MVT::i16); 87 case M68k::MOVI32ri: 88 return TII->ExpandMOVI(MIB, MVT::i32); 89 90 case M68k::MOVXd16d8: 91 return TII->ExpandMOVX_RR(MIB, MVT::i16, MVT::i8); 92 case M68k::MOVXd32d8: 93 return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i8); 94 case M68k::MOVXd32d16: 95 return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i16); 96 97 case M68k::MOVSXd16d8: 98 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i16, MVT::i8); 99 case M68k::MOVSXd32d8: 100 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i32, MVT::i8); 101 case M68k::MOVSXd32d16: 102 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i32, MVT::i16); 103 104 case M68k::MOVZXd16d8: 105 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i16, MVT::i8); 106 case M68k::MOVZXd32d8: 107 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i32, MVT::i8); 108 case M68k::MOVZXd32d16: 109 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i32, MVT::i16); 110 111 case M68k::MOVSXd16j8: 112 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i16, 113 MVT::i8); 114 case M68k::MOVSXd32j8: 115 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i32, 116 MVT::i8); 117 case M68k::MOVSXd32j16: 118 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rj), MVT::i32, 119 MVT::i16); 120 121 case M68k::MOVZXd16j8: 122 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i16, 123 MVT::i8); 124 case M68k::MOVZXd32j8: 125 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i32, 126 MVT::i8); 127 case M68k::MOVZXd32j16: 128 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rj), MVT::i32, 129 MVT::i16); 130 131 case M68k::MOVSXd16p8: 132 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i16, 133 MVT::i8); 134 case M68k::MOVSXd32p8: 135 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i32, 136 MVT::i8); 137 case M68k::MOVSXd32p16: 138 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rp), MVT::i32, 139 MVT::i16); 140 141 case M68k::MOVZXd16p8: 142 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i16, 143 MVT::i8); 144 case M68k::MOVZXd32p8: 145 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i32, 146 MVT::i8); 147 case M68k::MOVZXd32p16: 148 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rp), MVT::i32, 149 MVT::i16); 150 151 case M68k::MOVSXd16f8: 152 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i16, 153 MVT::i8); 154 case M68k::MOVSXd32f8: 155 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i32, 156 MVT::i8); 157 case M68k::MOVSXd32f16: 158 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rf), MVT::i32, 159 MVT::i16); 160 161 case M68k::MOVZXd16f8: 162 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i16, 163 MVT::i8); 164 case M68k::MOVZXd32f8: 165 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i32, 166 MVT::i8); 167 case M68k::MOVZXd32f16: 168 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rf), MVT::i32, 169 MVT::i16); 170 171 case M68k::MOVSXd16q8: 172 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i16, 173 MVT::i8); 174 case M68k::MOVSXd32q8: 175 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i32, 176 MVT::i8); 177 case M68k::MOVSXd32q16: 178 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16dq), MVT::i32, 179 MVT::i16); 180 181 case M68k::MOVZXd16q8: 182 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i16, 183 MVT::i8); 184 case M68k::MOVZXd32q8: 185 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i32, 186 MVT::i8); 187 case M68k::MOVZXd32q16: 188 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16dq), MVT::i32, 189 MVT::i16); 190 191 case M68k::MOV8cd: 192 return TII->ExpandCCR(MIB, /*IsToCCR=*/true); 193 case M68k::MOV8dc: 194 return TII->ExpandCCR(MIB, /*IsToCCR=*/false); 195 196 case M68k::MOVM8jm_P: 197 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 198 case M68k::MOVM16jm_P: 199 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 200 case M68k::MOVM32jm_P: 201 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); 202 203 case M68k::MOVM8pm_P: 204 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 205 case M68k::MOVM16pm_P: 206 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 207 case M68k::MOVM32pm_P: 208 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); 209 210 case M68k::MOVM8mj_P: 211 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 212 case M68k::MOVM16mj_P: 213 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 214 case M68k::MOVM32mj_P: 215 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); 216 217 case M68k::MOVM8mp_P: 218 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 219 case M68k::MOVM16mp_P: 220 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 221 case M68k::MOVM32mp_P: 222 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); 223 224 case M68k::TCRETURNq: 225 case M68k::TCRETURNj: { 226 MachineOperand &JumpTarget = MI.getOperand(0); 227 MachineOperand &StackAdjust = MI.getOperand(1); 228 assert(StackAdjust.isImm() && "Expecting immediate value."); 229 230 // Adjust stack pointer. 231 int StackAdj = StackAdjust.getImm(); 232 int MaxTCDelta = MFI->getTCReturnAddrDelta(); 233 int Offset = 0; 234 assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive"); 235 236 // Incoporate the retaddr area. 237 Offset = StackAdj - MaxTCDelta; 238 assert(Offset >= 0 && "Offset should never be negative"); 239 240 if (Offset) { 241 // Check for possible merge with preceding ADD instruction. 242 Offset += FL->mergeSPUpdates(MBB, MBBI, true); 243 FL->emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true); 244 } 245 246 // Jump to label or value in register. 247 if (Opcode == M68k::TCRETURNq) { 248 MachineInstrBuilder MIB = 249 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPq)); 250 if (JumpTarget.isGlobal()) { 251 MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), 252 JumpTarget.getTargetFlags()); 253 } else { 254 assert(JumpTarget.isSymbol()); 255 MIB.addExternalSymbol(JumpTarget.getSymbolName(), 256 JumpTarget.getTargetFlags()); 257 } 258 } else { 259 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPj)) 260 .addReg(JumpTarget.getReg(), RegState::Kill); 261 } 262 263 MachineInstr &NewMI = *std::prev(MBBI); 264 NewMI.copyImplicitOps(*MBBI->getParent()->getParent(), *MBBI); 265 266 // Delete the pseudo instruction TCRETURN. 267 MBB.erase(MBBI); 268 269 return true; 270 } 271 case M68k::RET: { 272 if (MBB.getParent()->getFunction().getCallingConv() == 273 CallingConv::M68k_INTR) { 274 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTE)); 275 } else if (int64_t StackAdj = MBBI->getOperand(0).getImm(); StackAdj == 0) { 276 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); 277 } else { 278 // Copy return address from stack to a free address(A0 or A1) register 279 // TODO check if pseudo expand uses free address register 280 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1) 281 .addReg(M68k::SP); 282 283 // Adjust SP 284 FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true); 285 286 // Put the return address on stack 287 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja)) 288 .addReg(M68k::SP) 289 .addReg(M68k::A1); 290 291 // RTS 292 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); 293 } 294 295 // FIXME: Can rest of the operands be ignored, if there is any? 296 MBB.erase(MBBI); 297 return true; 298 } 299 } 300 llvm_unreachable("Previous switch has a fallthrough?"); 301 } 302 303 /// Expand all pseudo instructions contained in \p MBB. 304 /// \returns true if any expansion occurred for \p MBB. 305 bool M68kExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { 306 bool Modified = false; 307 308 // MBBI may be invalidated by the expansion. 309 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 310 while (MBBI != E) { 311 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 312 Modified |= ExpandMI(MBB, MBBI); 313 MBBI = NMBBI; 314 } 315 316 return Modified; 317 } 318 319 bool M68kExpandPseudo::runOnMachineFunction(MachineFunction &MF) { 320 STI = &MF.getSubtarget<M68kSubtarget>(); 321 TII = STI->getInstrInfo(); 322 TRI = STI->getRegisterInfo(); 323 MFI = MF.getInfo<M68kMachineFunctionInfo>(); 324 FL = STI->getFrameLowering(); 325 326 bool Modified = false; 327 for (MachineBasicBlock &MBB : MF) 328 Modified |= ExpandMBB(MBB); 329 return Modified; 330 } 331 332 /// Returns an instance of the pseudo instruction expansion pass. 333 FunctionPass *llvm::createM68kExpandPseudoPass() { 334 return new M68kExpandPseudo(); 335 } 336