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 default: 100 return Opc; 101 } 102 else 103 switch (MemSizeInBytes) { 104 case 4: 105 return Mips::LW; 106 case 2: 107 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu; 108 case 1: 109 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu; 110 default: 111 return Opc; 112 } 113 } 114 115 bool MipsInstructionSelector::select(MachineInstr &I, 116 CodeGenCoverage &CoverageInfo) const { 117 118 MachineBasicBlock &MBB = *I.getParent(); 119 MachineFunction &MF = *MBB.getParent(); 120 MachineRegisterInfo &MRI = MF.getRegInfo(); 121 122 if (!isPreISelGenericOpcode(I.getOpcode())) { 123 if (I.isCopy()) 124 return selectCopy(I, TII, MRI, TRI, RBI); 125 126 return true; 127 } 128 129 if (selectImpl(I, CoverageInfo)) { 130 return true; 131 } 132 133 MachineInstr *MI = nullptr; 134 using namespace TargetOpcode; 135 136 switch (I.getOpcode()) { 137 case G_GEP: { 138 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu)) 139 .add(I.getOperand(0)) 140 .add(I.getOperand(1)) 141 .add(I.getOperand(2)); 142 break; 143 } 144 case G_FRAME_INDEX: { 145 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 146 .add(I.getOperand(0)) 147 .add(I.getOperand(1)) 148 .addImm(0); 149 break; 150 } 151 case G_STORE: 152 case G_LOAD: 153 case G_ZEXTLOAD: 154 case G_SEXTLOAD: { 155 const unsigned DestReg = I.getOperand(0).getReg(); 156 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 157 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 158 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize(); 159 160 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32) 161 return false; 162 163 const unsigned NewOpc = 164 selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes); 165 if (NewOpc == I.getOpcode()) 166 return false; 167 168 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) 169 .add(I.getOperand(0)) 170 .add(I.getOperand(1)) 171 .addImm(0) 172 .addMemOperand(*I.memoperands_begin()); 173 break; 174 } 175 case G_UDIV: 176 case G_UREM: 177 case G_SDIV: 178 case G_SREM: { 179 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 180 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV; 181 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV; 182 183 MachineInstr *PseudoDIV, *PseudoMove; 184 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(), 185 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV)) 186 .addDef(HILOReg) 187 .add(I.getOperand(1)) 188 .add(I.getOperand(2)); 189 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI)) 190 return false; 191 192 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), 193 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI)) 194 .addDef(I.getOperand(0).getReg()) 195 .addUse(HILOReg); 196 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 197 return false; 198 199 I.eraseFromParent(); 200 return true; 201 } 202 case G_SELECT: { 203 // Handle operands with pointer type. 204 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I)) 205 .add(I.getOperand(0)) 206 .add(I.getOperand(2)) 207 .add(I.getOperand(1)) 208 .add(I.getOperand(3)); 209 break; 210 } 211 case G_CONSTANT: { 212 int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue(); 213 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 214 MachineInstr *LUi, *ORi; 215 216 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 217 .addDef(LUiReg) 218 .addImm(Imm >> 16); 219 220 ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi)) 221 .addDef(I.getOperand(0).getReg()) 222 .addUse(LUiReg) 223 .addImm(Imm & 0xFFFF); 224 225 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 226 return false; 227 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI)) 228 return false; 229 230 I.eraseFromParent(); 231 return true; 232 } 233 case G_GLOBAL_VALUE: { 234 if (MF.getTarget().isPositionIndependent()) 235 return false; 236 237 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal(); 238 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 239 MachineInstr *LUi, *ADDiu; 240 241 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 242 .addDef(LUiReg) 243 .addGlobalAddress(GVal); 244 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI); 245 246 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 247 .addDef(I.getOperand(0).getReg()) 248 .addUse(LUiReg) 249 .addGlobalAddress(GVal); 250 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 251 252 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 253 return false; 254 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 255 return false; 256 257 I.eraseFromParent(); 258 return true; 259 } 260 case G_ICMP: { 261 struct Instr { 262 unsigned Opcode, Def, LHS, RHS; 263 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS) 264 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){}; 265 266 bool hasImm() const { 267 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi) 268 return true; 269 return false; 270 } 271 }; 272 273 SmallVector<struct Instr, 2> Instructions; 274 unsigned ICMPReg = I.getOperand(0).getReg(); 275 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass); 276 unsigned LHS = I.getOperand(2).getReg(); 277 unsigned RHS = I.getOperand(3).getReg(); 278 CmpInst::Predicate Cond = 279 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate()); 280 281 switch (Cond) { 282 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1 283 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 284 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1); 285 break; 286 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS) 287 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 288 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp); 289 break; 290 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS 291 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS); 292 break; 293 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS) 294 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS); 295 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 296 break; 297 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS 298 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS); 299 break; 300 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS) 301 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS); 302 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 303 break; 304 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS 305 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS); 306 break; 307 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS) 308 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS); 309 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 310 break; 311 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS 312 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS); 313 break; 314 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS) 315 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS); 316 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 317 break; 318 default: 319 return false; 320 } 321 322 MachineIRBuilder B(I); 323 for (const struct Instr &Instruction : Instructions) { 324 MachineInstrBuilder MIB = B.buildInstr( 325 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS}); 326 327 if (Instruction.hasImm()) 328 MIB.addImm(Instruction.RHS); 329 else 330 MIB.addUse(Instruction.RHS); 331 332 if (!MIB.constrainAllUses(TII, TRI, RBI)) 333 return false; 334 } 335 336 I.eraseFromParent(); 337 return true; 338 } 339 default: 340 return false; 341 } 342 343 I.eraseFromParent(); 344 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 345 } 346 347 namespace llvm { 348 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM, 349 MipsSubtarget &Subtarget, 350 MipsRegisterBankInfo &RBI) { 351 return new MipsInstructionSelector(TM, Subtarget, RBI); 352 } 353 } // end namespace llvm 354