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 "MCTargetDesc/MipsInstPrinter.h" 15 #include "MipsMachineFunction.h" 16 #include "MipsRegisterBankInfo.h" 17 #include "MipsTargetMachine.h" 18 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" 19 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 20 21 #define DEBUG_TYPE "mips-isel" 22 23 using namespace llvm; 24 25 namespace { 26 27 #define GET_GLOBALISEL_PREDICATE_BITSET 28 #include "MipsGenGlobalISel.inc" 29 #undef GET_GLOBALISEL_PREDICATE_BITSET 30 31 class MipsInstructionSelector : public InstructionSelector { 32 public: 33 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI, 34 const MipsRegisterBankInfo &RBI); 35 36 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override; 37 static const char *getName() { return DEBUG_TYPE; } 38 39 private: 40 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 41 bool materialize32BitImm(Register DestReg, APInt Imm, 42 MachineIRBuilder &B) const; 43 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const; 44 const TargetRegisterClass * 45 getRegClassForTypeOnBank(unsigned OpSize, const RegisterBank &RB, 46 const RegisterBankInfo &RBI) const; 47 48 const MipsTargetMachine &TM; 49 const MipsSubtarget &STI; 50 const MipsInstrInfo &TII; 51 const MipsRegisterInfo &TRI; 52 const MipsRegisterBankInfo &RBI; 53 54 #define GET_GLOBALISEL_PREDICATES_DECL 55 #include "MipsGenGlobalISel.inc" 56 #undef GET_GLOBALISEL_PREDICATES_DECL 57 58 #define GET_GLOBALISEL_TEMPORARIES_DECL 59 #include "MipsGenGlobalISel.inc" 60 #undef GET_GLOBALISEL_TEMPORARIES_DECL 61 }; 62 63 } // end anonymous namespace 64 65 #define GET_GLOBALISEL_IMPL 66 #include "MipsGenGlobalISel.inc" 67 #undef GET_GLOBALISEL_IMPL 68 69 MipsInstructionSelector::MipsInstructionSelector( 70 const MipsTargetMachine &TM, const MipsSubtarget &STI, 71 const MipsRegisterBankInfo &RBI) 72 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), 73 TRI(*STI.getRegisterInfo()), RBI(RBI), 74 75 #define GET_GLOBALISEL_PREDICATES_INIT 76 #include "MipsGenGlobalISel.inc" 77 #undef GET_GLOBALISEL_PREDICATES_INIT 78 #define GET_GLOBALISEL_TEMPORARIES_INIT 79 #include "MipsGenGlobalISel.inc" 80 #undef GET_GLOBALISEL_TEMPORARIES_INIT 81 { 82 } 83 84 bool MipsInstructionSelector::selectCopy(MachineInstr &I, 85 MachineRegisterInfo &MRI) const { 86 Register DstReg = I.getOperand(0).getReg(); 87 if (TargetRegisterInfo::isPhysicalRegister(DstReg)) 88 return true; 89 90 const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI); 91 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits(); 92 93 const TargetRegisterClass *RC = &Mips::GPR32RegClass; 94 if (RegBank->getID() == Mips::FPRBRegBankID) { 95 if (DstSize == 32) 96 RC = &Mips::FGR32RegClass; 97 else if (DstSize == 64) 98 RC = STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass; 99 else 100 llvm_unreachable("Unsupported destination size"); 101 } 102 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 103 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 104 << " operand\n"); 105 return false; 106 } 107 return true; 108 } 109 110 const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank( 111 unsigned OpSize, const RegisterBank &RB, 112 const RegisterBankInfo &RBI) const { 113 if (RB.getID() == Mips::GPRBRegBankID) 114 return &Mips::GPR32RegClass; 115 116 if (RB.getID() == Mips::FPRBRegBankID) 117 return OpSize == 32 118 ? &Mips::FGR32RegClass 119 : STI.hasMips32r6() || STI.isFP64bit() ? &Mips::FGR64RegClass 120 : &Mips::AFGR64RegClass; 121 122 llvm_unreachable("getRegClassForTypeOnBank can't find register class."); 123 return nullptr; 124 } 125 126 bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm, 127 MachineIRBuilder &B) const { 128 assert(Imm.getBitWidth() == 32 && "Unsupported immediate size."); 129 // Ori zero extends immediate. Used for values with zeros in high 16 bits. 130 if (Imm.getHiBits(16).isNullValue()) { 131 MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Register(Mips::ZERO)}) 132 .addImm(Imm.getLoBits(16).getLimitedValue()); 133 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI); 134 } 135 // Lui places immediate in high 16 bits and sets low 16 bits to zero. 136 if (Imm.getLoBits(16).isNullValue()) { 137 MachineInstr *Inst = B.buildInstr(Mips::LUi, {DestReg}, {}) 138 .addImm(Imm.getHiBits(16).getLimitedValue()); 139 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI); 140 } 141 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits. 142 if (Imm.isSignedIntN(16)) { 143 MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Register(Mips::ZERO)}) 144 .addImm(Imm.getLoBits(16).getLimitedValue()); 145 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI); 146 } 147 // Values that cannot be materialized with single immediate instruction. 148 Register LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass); 149 MachineInstr *LUi = B.buildInstr(Mips::LUi, {LUiReg}, {}) 150 .addImm(Imm.getHiBits(16).getLimitedValue()); 151 MachineInstr *ORi = B.buildInstr(Mips::ORi, {DestReg}, {LUiReg}) 152 .addImm(Imm.getLoBits(16).getLimitedValue()); 153 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 154 return false; 155 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI)) 156 return false; 157 return true; 158 } 159 160 /// Returning Opc indicates that we failed to select MIPS instruction opcode. 161 static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes, 162 unsigned RegBank, bool isFP64) { 163 bool isStore = Opc == TargetOpcode::G_STORE; 164 if (RegBank == Mips::GPRBRegBankID) { 165 if (isStore) 166 switch (MemSizeInBytes) { 167 case 4: 168 return Mips::SW; 169 case 2: 170 return Mips::SH; 171 case 1: 172 return Mips::SB; 173 default: 174 return Opc; 175 } 176 else 177 // Unspecified extending load is selected into zeroExtending load. 178 switch (MemSizeInBytes) { 179 case 4: 180 return Mips::LW; 181 case 2: 182 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu; 183 case 1: 184 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu; 185 default: 186 return Opc; 187 } 188 } 189 190 if (RegBank == Mips::FPRBRegBankID) { 191 switch (MemSizeInBytes) { 192 case 4: 193 return isStore ? Mips::SWC1 : Mips::LWC1; 194 case 8: 195 if (isFP64) 196 return isStore ? Mips::SDC164 : Mips::LDC164; 197 else 198 return isStore ? Mips::SDC1 : Mips::LDC1; 199 default: 200 return Opc; 201 } 202 } 203 return Opc; 204 } 205 206 bool MipsInstructionSelector::select(MachineInstr &I, 207 CodeGenCoverage &CoverageInfo) const { 208 209 MachineBasicBlock &MBB = *I.getParent(); 210 MachineFunction &MF = *MBB.getParent(); 211 MachineRegisterInfo &MRI = MF.getRegInfo(); 212 213 if (!isPreISelGenericOpcode(I.getOpcode())) { 214 if (I.isCopy()) 215 return selectCopy(I, MRI); 216 217 return true; 218 } 219 220 if (I.getOpcode() == Mips::G_MUL) { 221 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL)) 222 .add(I.getOperand(0)) 223 .add(I.getOperand(1)) 224 .add(I.getOperand(2)); 225 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI)) 226 return false; 227 Mul->getOperand(3).setIsDead(true); 228 Mul->getOperand(4).setIsDead(true); 229 230 I.eraseFromParent(); 231 return true; 232 } 233 234 if (selectImpl(I, CoverageInfo)) 235 return true; 236 237 MachineInstr *MI = nullptr; 238 using namespace TargetOpcode; 239 240 switch (I.getOpcode()) { 241 case G_UMULH: { 242 Register PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 243 MachineInstr *PseudoMULTu, *PseudoMove; 244 245 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu)) 246 .addDef(PseudoMULTuReg) 247 .add(I.getOperand(1)) 248 .add(I.getOperand(2)); 249 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI)) 250 return false; 251 252 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI)) 253 .addDef(I.getOperand(0).getReg()) 254 .addUse(PseudoMULTuReg); 255 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 256 return false; 257 258 I.eraseFromParent(); 259 return true; 260 } 261 case G_GEP: { 262 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu)) 263 .add(I.getOperand(0)) 264 .add(I.getOperand(1)) 265 .add(I.getOperand(2)); 266 break; 267 } 268 case G_INTTOPTR: 269 case G_PTRTOINT: { 270 I.setDesc(TII.get(COPY)); 271 return selectCopy(I, MRI); 272 } 273 case G_FRAME_INDEX: { 274 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 275 .add(I.getOperand(0)) 276 .add(I.getOperand(1)) 277 .addImm(0); 278 break; 279 } 280 case G_BRCOND: { 281 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE)) 282 .add(I.getOperand(0)) 283 .addUse(Mips::ZERO) 284 .add(I.getOperand(1)); 285 break; 286 } 287 case G_PHI: { 288 const Register DestReg = I.getOperand(0).getReg(); 289 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 290 291 const TargetRegisterClass *DefRC = nullptr; 292 if (TargetRegisterInfo::isPhysicalRegister(DestReg)) 293 DefRC = TRI.getRegClass(DestReg); 294 else 295 DefRC = getRegClassForTypeOnBank(OpSize, 296 *RBI.getRegBank(DestReg, MRI, TRI), RBI); 297 298 I.setDesc(TII.get(TargetOpcode::PHI)); 299 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI); 300 } 301 case G_STORE: 302 case G_LOAD: 303 case G_ZEXTLOAD: 304 case G_SEXTLOAD: { 305 const Register DestReg = I.getOperand(0).getReg(); 306 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 307 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 308 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize(); 309 310 if (DestRegBank == Mips::GPRBRegBankID && OpSize != 32) 311 return false; 312 313 if (DestRegBank == Mips::FPRBRegBankID && OpSize != 32 && OpSize != 64) 314 return false; 315 316 const unsigned NewOpc = selectLoadStoreOpCode( 317 I.getOpcode(), OpMemSizeInBytes, DestRegBank, STI.isFP64bit()); 318 if (NewOpc == I.getOpcode()) 319 return false; 320 321 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) 322 .add(I.getOperand(0)) 323 .add(I.getOperand(1)) 324 .addImm(0) 325 .addMemOperand(*I.memoperands_begin()); 326 break; 327 } 328 case G_UDIV: 329 case G_UREM: 330 case G_SDIV: 331 case G_SREM: { 332 Register HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 333 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV; 334 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV; 335 336 MachineInstr *PseudoDIV, *PseudoMove; 337 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(), 338 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV)) 339 .addDef(HILOReg) 340 .add(I.getOperand(1)) 341 .add(I.getOperand(2)); 342 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI)) 343 return false; 344 345 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), 346 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI)) 347 .addDef(I.getOperand(0).getReg()) 348 .addUse(HILOReg); 349 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 350 return false; 351 352 I.eraseFromParent(); 353 return true; 354 } 355 case G_SELECT: { 356 // Handle operands with pointer type. 357 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I)) 358 .add(I.getOperand(0)) 359 .add(I.getOperand(2)) 360 .add(I.getOperand(1)) 361 .add(I.getOperand(3)); 362 break; 363 } 364 case G_CONSTANT: { 365 MachineIRBuilder B(I); 366 if (!materialize32BitImm(I.getOperand(0).getReg(), 367 I.getOperand(1).getCImm()->getValue(), B)) 368 return false; 369 370 I.eraseFromParent(); 371 return true; 372 } 373 case G_FCONSTANT: { 374 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF(); 375 APInt APImm = FPimm.bitcastToAPInt(); 376 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits(); 377 378 if (Size == 32) { 379 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 380 MachineIRBuilder B(I); 381 if (!materialize32BitImm(GPRReg, APImm, B)) 382 return false; 383 384 MachineInstrBuilder MTC1 = 385 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg}); 386 if (!MTC1.constrainAllUses(TII, TRI, RBI)) 387 return false; 388 } 389 if (Size == 64) { 390 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass); 391 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass); 392 MachineIRBuilder B(I); 393 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B)) 394 return false; 395 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B)) 396 return false; 397 398 MachineInstrBuilder PairF64 = B.buildInstr( 399 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, 400 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh}); 401 if (!PairF64.constrainAllUses(TII, TRI, RBI)) 402 return false; 403 } 404 405 I.eraseFromParent(); 406 return true; 407 } 408 case G_FABS: { 409 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits(); 410 unsigned FABSOpcode = 411 Size == 32 ? Mips::FABS_S 412 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32; 413 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode)) 414 .add(I.getOperand(0)) 415 .add(I.getOperand(1)); 416 break; 417 } 418 case G_FPTOSI: { 419 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits(); 420 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits(); 421 (void)ToSize; 422 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI"); 423 assert((FromSize == 32 || FromSize == 64) && 424 "Unsupported floating point size for G_FPTOSI"); 425 426 unsigned Opcode; 427 if (FromSize == 32) 428 Opcode = Mips::TRUNC_W_S; 429 else 430 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32; 431 unsigned ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass); 432 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode)) 433 .addDef(ResultInFPR) 434 .addUse(I.getOperand(1).getReg()); 435 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI)) 436 return false; 437 438 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1)) 439 .addDef(I.getOperand(0).getReg()) 440 .addUse(ResultInFPR); 441 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI)) 442 return false; 443 444 I.eraseFromParent(); 445 return true; 446 } 447 case G_GLOBAL_VALUE: { 448 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal(); 449 if (MF.getTarget().isPositionIndependent()) { 450 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW)) 451 .addDef(I.getOperand(0).getReg()) 452 .addReg(MF.getInfo<MipsFunctionInfo>() 453 ->getGlobalBaseRegForGlobalISel()) 454 .addGlobalAddress(GVal); 455 // Global Values that don't have local linkage are handled differently 456 // when they are part of call sequence. MipsCallLowering::lowerCall 457 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds 458 // MO_GOT_CALL flag when Callee doesn't have local linkage. 459 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL) 460 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL); 461 else 462 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT); 463 LWGOT->addMemOperand( 464 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF), 465 MachineMemOperand::MOLoad, 4, 4)); 466 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI)) 467 return false; 468 469 if (GVal->hasLocalLinkage()) { 470 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass); 471 LWGOT->getOperand(0).setReg(LWGOTDef); 472 473 MachineInstr *ADDiu = 474 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 475 .addDef(I.getOperand(0).getReg()) 476 .addReg(LWGOTDef) 477 .addGlobalAddress(GVal); 478 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 479 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 480 return false; 481 } 482 } else { 483 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 484 485 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 486 .addDef(LUiReg) 487 .addGlobalAddress(GVal); 488 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI); 489 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 490 return false; 491 492 MachineInstr *ADDiu = 493 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 494 .addDef(I.getOperand(0).getReg()) 495 .addUse(LUiReg) 496 .addGlobalAddress(GVal); 497 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 498 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 499 return false; 500 } 501 I.eraseFromParent(); 502 return true; 503 } 504 case G_ICMP: { 505 struct Instr { 506 unsigned Opcode; 507 Register Def, LHS, RHS; 508 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS) 509 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){}; 510 511 bool hasImm() const { 512 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi) 513 return true; 514 return false; 515 } 516 }; 517 518 SmallVector<struct Instr, 2> Instructions; 519 Register ICMPReg = I.getOperand(0).getReg(); 520 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass); 521 Register LHS = I.getOperand(2).getReg(); 522 Register RHS = I.getOperand(3).getReg(); 523 CmpInst::Predicate Cond = 524 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate()); 525 526 switch (Cond) { 527 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1 528 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 529 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1); 530 break; 531 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS) 532 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 533 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp); 534 break; 535 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS 536 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS); 537 break; 538 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS) 539 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS); 540 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 541 break; 542 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS 543 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS); 544 break; 545 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS) 546 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS); 547 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 548 break; 549 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS 550 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS); 551 break; 552 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS) 553 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS); 554 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 555 break; 556 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS 557 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS); 558 break; 559 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS) 560 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS); 561 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 562 break; 563 default: 564 return false; 565 } 566 567 MachineIRBuilder B(I); 568 for (const struct Instr &Instruction : Instructions) { 569 MachineInstrBuilder MIB = B.buildInstr( 570 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS}); 571 572 if (Instruction.hasImm()) 573 MIB.addImm(Instruction.RHS); 574 else 575 MIB.addUse(Instruction.RHS); 576 577 if (!MIB.constrainAllUses(TII, TRI, RBI)) 578 return false; 579 } 580 581 I.eraseFromParent(); 582 return true; 583 } 584 case G_FCMP: { 585 unsigned MipsFCMPCondCode; 586 bool isLogicallyNegated; 587 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>( 588 I.getOperand(1).getPredicate())) { 589 case CmpInst::FCMP_UNO: // Unordered 590 case CmpInst::FCMP_ORD: // Ordered (OR) 591 MipsFCMPCondCode = Mips::FCOND_UN; 592 isLogicallyNegated = Cond != CmpInst::FCMP_UNO; 593 break; 594 case CmpInst::FCMP_OEQ: // Equal 595 case CmpInst::FCMP_UNE: // Not Equal (NEQ) 596 MipsFCMPCondCode = Mips::FCOND_OEQ; 597 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ; 598 break; 599 case CmpInst::FCMP_UEQ: // Unordered or Equal 600 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL) 601 MipsFCMPCondCode = Mips::FCOND_UEQ; 602 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ; 603 break; 604 case CmpInst::FCMP_OLT: // Ordered or Less Than 605 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE) 606 MipsFCMPCondCode = Mips::FCOND_OLT; 607 isLogicallyNegated = Cond != CmpInst::FCMP_OLT; 608 break; 609 case CmpInst::FCMP_ULT: // Unordered or Less Than 610 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE) 611 MipsFCMPCondCode = Mips::FCOND_ULT; 612 isLogicallyNegated = Cond != CmpInst::FCMP_ULT; 613 break; 614 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal 615 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT) 616 MipsFCMPCondCode = Mips::FCOND_OLE; 617 isLogicallyNegated = Cond != CmpInst::FCMP_OLE; 618 break; 619 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal 620 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT) 621 MipsFCMPCondCode = Mips::FCOND_ULE; 622 isLogicallyNegated = Cond != CmpInst::FCMP_ULE; 623 break; 624 default: 625 return false; 626 } 627 628 // Default compare result in gpr register will be `true`. 629 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false 630 // using MOVF_I. When orignal predicate (Cond) is logically negated 631 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used. 632 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I; 633 634 unsigned TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 635 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 636 .addDef(TrueInReg) 637 .addUse(Mips::ZERO) 638 .addImm(1); 639 640 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits(); 641 unsigned FCMPOpcode = 642 Size == 32 ? Mips::FCMP_S32 643 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32; 644 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode)) 645 .addUse(I.getOperand(2).getReg()) 646 .addUse(I.getOperand(3).getReg()) 647 .addImm(MipsFCMPCondCode); 648 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI)) 649 return false; 650 651 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode)) 652 .addDef(I.getOperand(0).getReg()) 653 .addUse(Mips::ZERO) 654 .addUse(Mips::FCC0) 655 .addUse(TrueInReg); 656 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI)) 657 return false; 658 659 I.eraseFromParent(); 660 return true; 661 } 662 default: 663 return false; 664 } 665 666 I.eraseFromParent(); 667 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 668 } 669 670 namespace llvm { 671 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM, 672 MipsSubtarget &Subtarget, 673 MipsRegisterBankInfo &RBI) { 674 return new MipsInstructionSelector(TM, Subtarget, RBI); 675 } 676 } // end namespace llvm 677