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 bool materialize32BitImm(unsigned DestReg, APInt Imm, 40 MachineIRBuilder &B) const; 41 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const; 42 43 const MipsTargetMachine &TM; 44 const MipsSubtarget &STI; 45 const MipsInstrInfo &TII; 46 const MipsRegisterInfo &TRI; 47 const MipsRegisterBankInfo &RBI; 48 49 #define GET_GLOBALISEL_PREDICATES_DECL 50 #include "MipsGenGlobalISel.inc" 51 #undef GET_GLOBALISEL_PREDICATES_DECL 52 53 #define GET_GLOBALISEL_TEMPORARIES_DECL 54 #include "MipsGenGlobalISel.inc" 55 #undef GET_GLOBALISEL_TEMPORARIES_DECL 56 }; 57 58 } // end anonymous namespace 59 60 #define GET_GLOBALISEL_IMPL 61 #include "MipsGenGlobalISel.inc" 62 #undef GET_GLOBALISEL_IMPL 63 64 MipsInstructionSelector::MipsInstructionSelector( 65 const MipsTargetMachine &TM, const MipsSubtarget &STI, 66 const MipsRegisterBankInfo &RBI) 67 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), 68 TRI(*STI.getRegisterInfo()), RBI(RBI), 69 70 #define GET_GLOBALISEL_PREDICATES_INIT 71 #include "MipsGenGlobalISel.inc" 72 #undef GET_GLOBALISEL_PREDICATES_INIT 73 #define GET_GLOBALISEL_TEMPORARIES_INIT 74 #include "MipsGenGlobalISel.inc" 75 #undef GET_GLOBALISEL_TEMPORARIES_INIT 76 { 77 } 78 79 bool MipsInstructionSelector::selectCopy(MachineInstr &I, 80 MachineRegisterInfo &MRI) const { 81 unsigned DstReg = I.getOperand(0).getReg(); 82 if (TargetRegisterInfo::isPhysicalRegister(DstReg)) 83 return true; 84 85 const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI); 86 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits(); 87 88 const TargetRegisterClass *RC = &Mips::GPR32RegClass; 89 if (RegBank->getID() == Mips::FPRBRegBankID) { 90 if (DstSize == 32) 91 RC = &Mips::FGR32RegClass; 92 else if (DstSize == 64) 93 RC = STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass; 94 else 95 llvm_unreachable("Unsupported destination size"); 96 } 97 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 98 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 99 << " operand\n"); 100 return false; 101 } 102 return true; 103 } 104 105 bool MipsInstructionSelector::materialize32BitImm(unsigned DestReg, APInt Imm, 106 MachineIRBuilder &B) const { 107 assert(Imm.getBitWidth() == 32 && "Unsupported immediate size."); 108 // Ori zero extends immediate. Used for values with zeros in high 16 bits. 109 if (Imm.getHiBits(16).isNullValue()) { 110 MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Mips::ZERO}) 111 .addImm(Imm.getLoBits(16).getLimitedValue()); 112 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI); 113 } 114 // Lui places immediate in high 16 bits and sets low 16 bits to zero. 115 if (Imm.getLoBits(16).isNullValue()) { 116 MachineInstr *Inst = B.buildInstr(Mips::LUi, {DestReg}, {}) 117 .addImm(Imm.getHiBits(16).getLimitedValue()); 118 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI); 119 } 120 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits. 121 if (Imm.isSignedIntN(16)) { 122 MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Mips::ZERO}) 123 .addImm(Imm.getLoBits(16).getLimitedValue()); 124 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI); 125 } 126 // Values that cannot be materialized with single immediate instruction. 127 unsigned LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass); 128 MachineInstr *LUi = B.buildInstr(Mips::LUi, {LUiReg}, {}) 129 .addImm(Imm.getHiBits(16).getLimitedValue()); 130 MachineInstr *ORi = B.buildInstr(Mips::ORi, {DestReg}, {LUiReg}) 131 .addImm(Imm.getLoBits(16).getLimitedValue()); 132 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 133 return false; 134 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI)) 135 return false; 136 return true; 137 } 138 139 /// Returning Opc indicates that we failed to select MIPS instruction opcode. 140 static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes) { 141 if (Opc == TargetOpcode::G_STORE) 142 switch (MemSizeInBytes) { 143 case 4: 144 return Mips::SW; 145 case 2: 146 return Mips::SH; 147 case 1: 148 return Mips::SB; 149 default: 150 return Opc; 151 } 152 else 153 // Unspecified extending load is selected into zeroExtending load. 154 switch (MemSizeInBytes) { 155 case 4: 156 return Mips::LW; 157 case 2: 158 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu; 159 case 1: 160 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu; 161 default: 162 return Opc; 163 } 164 } 165 166 bool MipsInstructionSelector::select(MachineInstr &I, 167 CodeGenCoverage &CoverageInfo) const { 168 169 MachineBasicBlock &MBB = *I.getParent(); 170 MachineFunction &MF = *MBB.getParent(); 171 MachineRegisterInfo &MRI = MF.getRegInfo(); 172 173 if (!isPreISelGenericOpcode(I.getOpcode())) { 174 if (I.isCopy()) 175 return selectCopy(I, MRI); 176 177 return true; 178 } 179 180 if (I.getOpcode() == Mips::G_MUL) { 181 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL)) 182 .add(I.getOperand(0)) 183 .add(I.getOperand(1)) 184 .add(I.getOperand(2)); 185 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI)) 186 return false; 187 Mul->getOperand(3).setIsDead(true); 188 Mul->getOperand(4).setIsDead(true); 189 190 I.eraseFromParent(); 191 return true; 192 } 193 194 if (selectImpl(I, CoverageInfo)) 195 return true; 196 197 MachineInstr *MI = nullptr; 198 using namespace TargetOpcode; 199 200 switch (I.getOpcode()) { 201 case G_UMULH: { 202 unsigned PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 203 MachineInstr *PseudoMULTu, *PseudoMove; 204 205 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu)) 206 .addDef(PseudoMULTuReg) 207 .add(I.getOperand(1)) 208 .add(I.getOperand(2)); 209 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI)) 210 return false; 211 212 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI)) 213 .addDef(I.getOperand(0).getReg()) 214 .addUse(PseudoMULTuReg); 215 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 216 return false; 217 218 I.eraseFromParent(); 219 return true; 220 } 221 case G_GEP: { 222 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu)) 223 .add(I.getOperand(0)) 224 .add(I.getOperand(1)) 225 .add(I.getOperand(2)); 226 break; 227 } 228 case G_FRAME_INDEX: { 229 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 230 .add(I.getOperand(0)) 231 .add(I.getOperand(1)) 232 .addImm(0); 233 break; 234 } 235 case G_BRCOND: { 236 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE)) 237 .add(I.getOperand(0)) 238 .addUse(Mips::ZERO) 239 .add(I.getOperand(1)); 240 break; 241 } 242 case G_PHI: { 243 const unsigned DestReg = I.getOperand(0).getReg(); 244 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 245 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 246 247 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32) 248 return false; 249 250 const TargetRegisterClass *DefRC = &Mips::GPR32RegClass; 251 I.setDesc(TII.get(TargetOpcode::PHI)); 252 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI); 253 } 254 case G_STORE: 255 case G_LOAD: 256 case G_ZEXTLOAD: 257 case G_SEXTLOAD: { 258 const unsigned DestReg = I.getOperand(0).getReg(); 259 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 260 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 261 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize(); 262 263 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32) 264 return false; 265 266 const unsigned NewOpc = 267 selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes); 268 if (NewOpc == I.getOpcode()) 269 return false; 270 271 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) 272 .add(I.getOperand(0)) 273 .add(I.getOperand(1)) 274 .addImm(0) 275 .addMemOperand(*I.memoperands_begin()); 276 break; 277 } 278 case G_UDIV: 279 case G_UREM: 280 case G_SDIV: 281 case G_SREM: { 282 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 283 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV; 284 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV; 285 286 MachineInstr *PseudoDIV, *PseudoMove; 287 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(), 288 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV)) 289 .addDef(HILOReg) 290 .add(I.getOperand(1)) 291 .add(I.getOperand(2)); 292 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI)) 293 return false; 294 295 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), 296 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI)) 297 .addDef(I.getOperand(0).getReg()) 298 .addUse(HILOReg); 299 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 300 return false; 301 302 I.eraseFromParent(); 303 return true; 304 } 305 case G_SELECT: { 306 // Handle operands with pointer type. 307 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I)) 308 .add(I.getOperand(0)) 309 .add(I.getOperand(2)) 310 .add(I.getOperand(1)) 311 .add(I.getOperand(3)); 312 break; 313 } 314 case G_CONSTANT: { 315 MachineIRBuilder B(I); 316 if (!materialize32BitImm(I.getOperand(0).getReg(), 317 I.getOperand(1).getCImm()->getValue(), B)) 318 return false; 319 320 I.eraseFromParent(); 321 return true; 322 } 323 case G_FCONSTANT: { 324 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF(); 325 APInt APImm = FPimm.bitcastToAPInt(); 326 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits(); 327 328 if (Size == 32) { 329 unsigned GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 330 MachineIRBuilder B(I); 331 if (!materialize32BitImm(GPRReg, APImm, B)) 332 return false; 333 334 MachineInstrBuilder MTC1 = 335 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg}); 336 if (!MTC1.constrainAllUses(TII, TRI, RBI)) 337 return false; 338 } 339 if (Size == 64) { 340 unsigned GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass); 341 unsigned GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass); 342 MachineIRBuilder B(I); 343 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B)) 344 return false; 345 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B)) 346 return false; 347 348 MachineInstrBuilder PairF64 = B.buildInstr( 349 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, 350 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh}); 351 if (!PairF64.constrainAllUses(TII, TRI, RBI)) 352 return false; 353 } 354 355 I.eraseFromParent(); 356 return true; 357 } 358 case G_GLOBAL_VALUE: { 359 if (MF.getTarget().isPositionIndependent()) 360 return false; 361 362 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal(); 363 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 364 MachineInstr *LUi, *ADDiu; 365 366 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 367 .addDef(LUiReg) 368 .addGlobalAddress(GVal); 369 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI); 370 371 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 372 .addDef(I.getOperand(0).getReg()) 373 .addUse(LUiReg) 374 .addGlobalAddress(GVal); 375 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 376 377 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 378 return false; 379 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 380 return false; 381 382 I.eraseFromParent(); 383 return true; 384 } 385 case G_ICMP: { 386 struct Instr { 387 unsigned Opcode, Def, LHS, RHS; 388 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS) 389 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){}; 390 391 bool hasImm() const { 392 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi) 393 return true; 394 return false; 395 } 396 }; 397 398 SmallVector<struct Instr, 2> Instructions; 399 unsigned ICMPReg = I.getOperand(0).getReg(); 400 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass); 401 unsigned LHS = I.getOperand(2).getReg(); 402 unsigned RHS = I.getOperand(3).getReg(); 403 CmpInst::Predicate Cond = 404 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate()); 405 406 switch (Cond) { 407 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1 408 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 409 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1); 410 break; 411 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS) 412 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 413 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp); 414 break; 415 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS 416 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS); 417 break; 418 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS) 419 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS); 420 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 421 break; 422 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS 423 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS); 424 break; 425 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS) 426 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS); 427 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 428 break; 429 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS 430 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS); 431 break; 432 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS) 433 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS); 434 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 435 break; 436 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS 437 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS); 438 break; 439 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS) 440 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS); 441 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 442 break; 443 default: 444 return false; 445 } 446 447 MachineIRBuilder B(I); 448 for (const struct Instr &Instruction : Instructions) { 449 MachineInstrBuilder MIB = B.buildInstr( 450 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS}); 451 452 if (Instruction.hasImm()) 453 MIB.addImm(Instruction.RHS); 454 else 455 MIB.addUse(Instruction.RHS); 456 457 if (!MIB.constrainAllUses(TII, TRI, RBI)) 458 return false; 459 } 460 461 I.eraseFromParent(); 462 return true; 463 } 464 default: 465 return false; 466 } 467 468 I.eraseFromParent(); 469 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 470 } 471 472 namespace llvm { 473 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM, 474 MipsSubtarget &Subtarget, 475 MipsRegisterBankInfo &RBI) { 476 return new MipsInstructionSelector(TM, Subtarget, RBI); 477 } 478 } // end namespace llvm 479