1 //===- MipsInstructionSelector.cpp ------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// \file 10 /// This file implements the targeting of the InstructionSelector class for 11 /// Mips. 12 /// \todo This should be generated by TableGen. 13 //===----------------------------------------------------------------------===// 14 15 #include "MipsRegisterBankInfo.h" 16 #include "MipsTargetMachine.h" 17 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" 18 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 19 20 #define DEBUG_TYPE "mips-isel" 21 22 using namespace llvm; 23 24 namespace { 25 26 #define GET_GLOBALISEL_PREDICATE_BITSET 27 #include "MipsGenGlobalISel.inc" 28 #undef GET_GLOBALISEL_PREDICATE_BITSET 29 30 class MipsInstructionSelector : public InstructionSelector { 31 public: 32 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI, 33 const MipsRegisterBankInfo &RBI); 34 35 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override; 36 static const char *getName() { return DEBUG_TYPE; } 37 38 private: 39 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 40 41 const MipsTargetMachine &TM; 42 const MipsSubtarget &STI; 43 const MipsInstrInfo &TII; 44 const MipsRegisterInfo &TRI; 45 const MipsRegisterBankInfo &RBI; 46 47 #define GET_GLOBALISEL_PREDICATES_DECL 48 #include "MipsGenGlobalISel.inc" 49 #undef GET_GLOBALISEL_PREDICATES_DECL 50 51 #define GET_GLOBALISEL_TEMPORARIES_DECL 52 #include "MipsGenGlobalISel.inc" 53 #undef GET_GLOBALISEL_TEMPORARIES_DECL 54 }; 55 56 } // end anonymous namespace 57 58 #define GET_GLOBALISEL_IMPL 59 #include "MipsGenGlobalISel.inc" 60 #undef GET_GLOBALISEL_IMPL 61 62 MipsInstructionSelector::MipsInstructionSelector( 63 const MipsTargetMachine &TM, const MipsSubtarget &STI, 64 const MipsRegisterBankInfo &RBI) 65 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), 66 TRI(*STI.getRegisterInfo()), RBI(RBI), 67 68 #define GET_GLOBALISEL_PREDICATES_INIT 69 #include "MipsGenGlobalISel.inc" 70 #undef GET_GLOBALISEL_PREDICATES_INIT 71 #define GET_GLOBALISEL_TEMPORARIES_INIT 72 #include "MipsGenGlobalISel.inc" 73 #undef GET_GLOBALISEL_TEMPORARIES_INIT 74 { 75 } 76 77 static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, 78 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, 79 const RegisterBankInfo &RBI) { 80 unsigned DstReg = I.getOperand(0).getReg(); 81 if (TargetRegisterInfo::isPhysicalRegister(DstReg)) 82 return true; 83 84 const TargetRegisterClass *RC = &Mips::GPR32RegClass; 85 86 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 87 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 88 << " operand\n"); 89 return false; 90 } 91 return true; 92 } 93 94 bool MipsInstructionSelector::select(MachineInstr &I, 95 CodeGenCoverage &CoverageInfo) const { 96 97 MachineBasicBlock &MBB = *I.getParent(); 98 MachineFunction &MF = *MBB.getParent(); 99 MachineRegisterInfo &MRI = MF.getRegInfo(); 100 101 if (!isPreISelGenericOpcode(I.getOpcode())) { 102 if (I.isCopy()) 103 return selectCopy(I, TII, MRI, TRI, RBI); 104 105 return true; 106 } 107 108 if (selectImpl(I, CoverageInfo)) { 109 return true; 110 } 111 112 MachineInstr *MI = nullptr; 113 using namespace TargetOpcode; 114 115 switch (I.getOpcode()) { 116 case G_GEP: { 117 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu)) 118 .add(I.getOperand(0)) 119 .add(I.getOperand(1)) 120 .add(I.getOperand(2)); 121 break; 122 } 123 case G_FRAME_INDEX: { 124 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 125 .add(I.getOperand(0)) 126 .add(I.getOperand(1)) 127 .addImm(0); 128 break; 129 } 130 case G_STORE: 131 case G_LOAD: { 132 const unsigned DestReg = I.getOperand(0).getReg(); 133 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID(); 134 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits(); 135 136 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32) 137 return false; 138 139 const unsigned NewOpc = I.getOpcode() == G_STORE ? Mips::SW : Mips::LW; 140 141 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) 142 .add(I.getOperand(0)) 143 .add(I.getOperand(1)) 144 .addImm(0) 145 .addMemOperand(*I.memoperands_begin()); 146 break; 147 } 148 case G_UDIV: 149 case G_UREM: 150 case G_SDIV: 151 case G_SREM: { 152 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass); 153 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV; 154 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV; 155 156 MachineInstr *PseudoDIV, *PseudoMove; 157 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(), 158 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV)) 159 .addDef(HILOReg) 160 .add(I.getOperand(1)) 161 .add(I.getOperand(2)); 162 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI)) 163 return false; 164 165 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), 166 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI)) 167 .addDef(I.getOperand(0).getReg()) 168 .addUse(HILOReg); 169 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI)) 170 return false; 171 172 I.eraseFromParent(); 173 return true; 174 } 175 case G_SELECT: { 176 // Handle operands with pointer type. 177 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I)) 178 .add(I.getOperand(0)) 179 .add(I.getOperand(2)) 180 .add(I.getOperand(1)) 181 .add(I.getOperand(3)); 182 break; 183 } 184 case G_CONSTANT: { 185 int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue(); 186 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 187 MachineInstr *LUi, *ORi; 188 189 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 190 .addDef(LUiReg) 191 .addImm(Imm >> 16); 192 193 ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi)) 194 .addDef(I.getOperand(0).getReg()) 195 .addUse(LUiReg) 196 .addImm(Imm & 0xFFFF); 197 198 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 199 return false; 200 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI)) 201 return false; 202 203 I.eraseFromParent(); 204 return true; 205 } 206 case G_GLOBAL_VALUE: { 207 if (MF.getTarget().isPositionIndependent()) 208 return false; 209 210 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal(); 211 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 212 MachineInstr *LUi, *ADDiu; 213 214 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 215 .addDef(LUiReg) 216 .addGlobalAddress(GVal); 217 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI); 218 219 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 220 .addDef(I.getOperand(0).getReg()) 221 .addUse(LUiReg) 222 .addGlobalAddress(GVal); 223 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 224 225 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 226 return false; 227 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 228 return false; 229 230 I.eraseFromParent(); 231 return true; 232 } 233 case G_ICMP: { 234 struct Instr { 235 unsigned Opcode, Def, LHS, RHS; 236 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS) 237 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){}; 238 239 bool hasImm() const { 240 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi) 241 return true; 242 return false; 243 } 244 }; 245 246 SmallVector<struct Instr, 2> Instructions; 247 unsigned ICMPReg = I.getOperand(0).getReg(); 248 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass); 249 unsigned LHS = I.getOperand(2).getReg(); 250 unsigned RHS = I.getOperand(3).getReg(); 251 CmpInst::Predicate Cond = 252 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate()); 253 254 switch (Cond) { 255 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1 256 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 257 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1); 258 break; 259 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS) 260 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 261 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp); 262 break; 263 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS 264 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS); 265 break; 266 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS) 267 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS); 268 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 269 break; 270 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS 271 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS); 272 break; 273 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS) 274 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS); 275 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 276 break; 277 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS 278 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS); 279 break; 280 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS) 281 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS); 282 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 283 break; 284 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS 285 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS); 286 break; 287 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS) 288 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS); 289 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 290 break; 291 default: 292 return false; 293 } 294 295 MachineIRBuilder B(I); 296 for (const struct Instr &Instruction : Instructions) { 297 MachineInstrBuilder MIB = B.buildInstr( 298 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS}); 299 300 if (Instruction.hasImm()) 301 MIB.addImm(Instruction.RHS); 302 else 303 MIB.addUse(Instruction.RHS); 304 305 if (!MIB.constrainAllUses(TII, TRI, RBI)) 306 return false; 307 } 308 309 I.eraseFromParent(); 310 return true; 311 } 312 default: 313 return false; 314 } 315 316 I.eraseFromParent(); 317 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 318 } 319 320 namespace llvm { 321 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM, 322 MipsSubtarget &Subtarget, 323 MipsRegisterBankInfo &RBI) { 324 return new MipsInstructionSelector(TM, Subtarget, RBI); 325 } 326 } // end namespace llvm 327