1 //===- MipsInstructionSelector.cpp ------------------------------*- 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 /// \file 9 /// This file implements the targeting of the InstructionSelector class for 10 /// Mips. 11 /// \todo This should be generated by TableGen. 12 //===----------------------------------------------------------------------===// 13 14 #include "MipsRegisterBankInfo.h" 15 #include "MipsTargetMachine.h" 16 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" 17 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 18 19 #define DEBUG_TYPE "mips-isel" 20 21 using namespace llvm; 22 23 namespace { 24 25 #define GET_GLOBALISEL_PREDICATE_BITSET 26 #include "MipsGenGlobalISel.inc" 27 #undef GET_GLOBALISEL_PREDICATE_BITSET 28 29 class MipsInstructionSelector : public InstructionSelector { 30 public: 31 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI, 32 const MipsRegisterBankInfo &RBI); 33 34 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override; 35 static const char *getName() { return DEBUG_TYPE; } 36 37 private: 38 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 39 40 const MipsTargetMachine &TM; 41 const MipsSubtarget &STI; 42 const MipsInstrInfo &TII; 43 const MipsRegisterInfo &TRI; 44 const MipsRegisterBankInfo &RBI; 45 46 #define GET_GLOBALISEL_PREDICATES_DECL 47 #include "MipsGenGlobalISel.inc" 48 #undef GET_GLOBALISEL_PREDICATES_DECL 49 50 #define GET_GLOBALISEL_TEMPORARIES_DECL 51 #include "MipsGenGlobalISel.inc" 52 #undef GET_GLOBALISEL_TEMPORARIES_DECL 53 }; 54 55 } // end anonymous namespace 56 57 #define GET_GLOBALISEL_IMPL 58 #include "MipsGenGlobalISel.inc" 59 #undef GET_GLOBALISEL_IMPL 60 61 MipsInstructionSelector::MipsInstructionSelector( 62 const MipsTargetMachine &TM, const MipsSubtarget &STI, 63 const MipsRegisterBankInfo &RBI) 64 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), 65 TRI(*STI.getRegisterInfo()), RBI(RBI), 66 67 #define GET_GLOBALISEL_PREDICATES_INIT 68 #include "MipsGenGlobalISel.inc" 69 #undef GET_GLOBALISEL_PREDICATES_INIT 70 #define GET_GLOBALISEL_TEMPORARIES_INIT 71 #include "MipsGenGlobalISel.inc" 72 #undef GET_GLOBALISEL_TEMPORARIES_INIT 73 { 74 } 75 76 static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, 77 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, 78 const RegisterBankInfo &RBI) { 79 unsigned DstReg = I.getOperand(0).getReg(); 80 if (TargetRegisterInfo::isPhysicalRegister(DstReg)) 81 return true; 82 83 const TargetRegisterClass *RC = &Mips::GPR32RegClass; 84 85 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 86 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 87 << " operand\n"); 88 return false; 89 } 90 return true; 91 } 92 93 /// Returning Opc indicates that we failed to select MIPS instruction opcode. 94 static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes) { 95 if (Opc == TargetOpcode::G_STORE) 96 switch (MemSizeInBytes) { 97 case 4: 98 return Mips::SW; 99 case 2: 100 return Mips::SH; 101 case 1: 102 return Mips::SB; 103 default: 104 return Opc; 105 } 106 else 107 // Unspecified extending load is selected into zeroExtending load. 108 switch (MemSizeInBytes) { 109 case 4: 110 return Mips::LW; 111 case 2: 112 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu; 113 case 1: 114 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu; 115 default: 116 return Opc; 117 } 118 } 119 120 bool MipsInstructionSelector::select(MachineInstr &I, 121 CodeGenCoverage &CoverageInfo) const { 122 123 MachineBasicBlock &MBB = *I.getParent(); 124 MachineFunction &MF = *MBB.getParent(); 125 MachineRegisterInfo &MRI = MF.getRegInfo(); 126 127 if (!isPreISelGenericOpcode(I.getOpcode())) { 128 if (I.isCopy()) 129 return selectCopy(I, TII, MRI, TRI, RBI); 130 131 return true; 132 } 133 134 if (I.getOpcode() == Mips::G_MUL) { 135 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL)) 136 .add(I.getOperand(0)) 137 .add(I.getOperand(1)) 138 .add(I.getOperand(2)); 139 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI)) 140 return false; 141 Mul->getOperand(3).setIsDead(true); 142 Mul->getOperand(4).setIsDead(true); 143 144 I.eraseFromParent(); 145 return true; 146 } 147 148 if (selectImpl(I, CoverageInfo)) 149 return true; 150 151 MachineInstr *MI = nullptr; 152 using namespace TargetOpcode; 153 154 switch (I.getOpcode()) { 155 case G_UMULH: { 156 unsigned PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 157 MachineInstr *PseudoMULTu, *PseudoMove; 158 159 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu)) 160 .addDef(PseudoMULTuReg) 161 .add(I.getOperand(1)) 162 .add(I.getOperand(2)); 163 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI)) 164 return false; 165 166 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI)) 167 .addDef(I.getOperand(0).getReg()) 168 .addUse(PseudoMULTuReg); 169 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 170 return false; 171 172 I.eraseFromParent(); 173 return true; 174 } 175 case G_GEP: { 176 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu)) 177 .add(I.getOperand(0)) 178 .add(I.getOperand(1)) 179 .add(I.getOperand(2)); 180 break; 181 } 182 case G_FRAME_INDEX: { 183 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 184 .add(I.getOperand(0)) 185 .add(I.getOperand(1)) 186 .addImm(0); 187 break; 188 } 189 case G_BRCOND: { 190 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE)) 191 .add(I.getOperand(0)) 192 .addUse(Mips::ZERO) 193 .add(I.getOperand(1)); 194 break; 195 } 196 case G_PHI: { 197 const unsigned DestReg = I.getOperand(0).getReg(); 198 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 199 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 200 201 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32) 202 return false; 203 204 const TargetRegisterClass *DefRC = &Mips::GPR32RegClass; 205 I.setDesc(TII.get(TargetOpcode::PHI)); 206 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI); 207 } 208 case G_STORE: 209 case G_LOAD: 210 case G_ZEXTLOAD: 211 case G_SEXTLOAD: { 212 const unsigned DestReg = I.getOperand(0).getReg(); 213 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 214 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 215 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize(); 216 217 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32) 218 return false; 219 220 const unsigned NewOpc = 221 selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes); 222 if (NewOpc == I.getOpcode()) 223 return false; 224 225 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) 226 .add(I.getOperand(0)) 227 .add(I.getOperand(1)) 228 .addImm(0) 229 .addMemOperand(*I.memoperands_begin()); 230 break; 231 } 232 case G_UDIV: 233 case G_UREM: 234 case G_SDIV: 235 case G_SREM: { 236 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 237 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV; 238 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV; 239 240 MachineInstr *PseudoDIV, *PseudoMove; 241 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(), 242 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV)) 243 .addDef(HILOReg) 244 .add(I.getOperand(1)) 245 .add(I.getOperand(2)); 246 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI)) 247 return false; 248 249 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), 250 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI)) 251 .addDef(I.getOperand(0).getReg()) 252 .addUse(HILOReg); 253 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 254 return false; 255 256 I.eraseFromParent(); 257 return true; 258 } 259 case G_SELECT: { 260 // Handle operands with pointer type. 261 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I)) 262 .add(I.getOperand(0)) 263 .add(I.getOperand(2)) 264 .add(I.getOperand(1)) 265 .add(I.getOperand(3)); 266 break; 267 } 268 case G_CONSTANT: { 269 int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue(); 270 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 271 MachineInstr *LUi, *ORi; 272 273 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 274 .addDef(LUiReg) 275 .addImm(Imm >> 16); 276 277 ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi)) 278 .addDef(I.getOperand(0).getReg()) 279 .addUse(LUiReg) 280 .addImm(Imm & 0xFFFF); 281 282 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 283 return false; 284 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI)) 285 return false; 286 287 I.eraseFromParent(); 288 return true; 289 } 290 case G_GLOBAL_VALUE: { 291 if (MF.getTarget().isPositionIndependent()) 292 return false; 293 294 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal(); 295 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 296 MachineInstr *LUi, *ADDiu; 297 298 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 299 .addDef(LUiReg) 300 .addGlobalAddress(GVal); 301 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI); 302 303 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 304 .addDef(I.getOperand(0).getReg()) 305 .addUse(LUiReg) 306 .addGlobalAddress(GVal); 307 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 308 309 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 310 return false; 311 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 312 return false; 313 314 I.eraseFromParent(); 315 return true; 316 } 317 case G_ICMP: { 318 struct Instr { 319 unsigned Opcode, Def, LHS, RHS; 320 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS) 321 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){}; 322 323 bool hasImm() const { 324 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi) 325 return true; 326 return false; 327 } 328 }; 329 330 SmallVector<struct Instr, 2> Instructions; 331 unsigned ICMPReg = I.getOperand(0).getReg(); 332 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass); 333 unsigned LHS = I.getOperand(2).getReg(); 334 unsigned RHS = I.getOperand(3).getReg(); 335 CmpInst::Predicate Cond = 336 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate()); 337 338 switch (Cond) { 339 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1 340 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 341 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1); 342 break; 343 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS) 344 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 345 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp); 346 break; 347 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS 348 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS); 349 break; 350 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS) 351 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS); 352 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 353 break; 354 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS 355 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS); 356 break; 357 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS) 358 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS); 359 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 360 break; 361 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS 362 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS); 363 break; 364 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS) 365 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS); 366 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 367 break; 368 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS 369 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS); 370 break; 371 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS) 372 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS); 373 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 374 break; 375 default: 376 return false; 377 } 378 379 MachineIRBuilder B(I); 380 for (const struct Instr &Instruction : Instructions) { 381 MachineInstrBuilder MIB = B.buildInstr( 382 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS}); 383 384 if (Instruction.hasImm()) 385 MIB.addImm(Instruction.RHS); 386 else 387 MIB.addUse(Instruction.RHS); 388 389 if (!MIB.constrainAllUses(TII, TRI, RBI)) 390 return false; 391 } 392 393 I.eraseFromParent(); 394 return true; 395 } 396 default: 397 return false; 398 } 399 400 I.eraseFromParent(); 401 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 402 } 403 404 namespace llvm { 405 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM, 406 MipsSubtarget &Subtarget, 407 MipsRegisterBankInfo &RBI) { 408 return new MipsInstructionSelector(TM, Subtarget, RBI); 409 } 410 } // end namespace llvm 411