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_CONSTANT: { 176 int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue(); 177 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 178 MachineInstr *LUi, *ORi; 179 180 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 181 .addDef(LUiReg) 182 .addImm(Imm >> 16); 183 184 ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi)) 185 .addDef(I.getOperand(0).getReg()) 186 .addUse(LUiReg) 187 .addImm(Imm & 0xFFFF); 188 189 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 190 return false; 191 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI)) 192 return false; 193 194 I.eraseFromParent(); 195 return true; 196 } 197 case G_GLOBAL_VALUE: { 198 if (MF.getTarget().isPositionIndependent()) 199 return false; 200 201 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal(); 202 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass); 203 MachineInstr *LUi, *ADDiu; 204 205 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi)) 206 .addDef(LUiReg) 207 .addGlobalAddress(GVal); 208 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI); 209 210 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu)) 211 .addDef(I.getOperand(0).getReg()) 212 .addUse(LUiReg) 213 .addGlobalAddress(GVal); 214 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO); 215 216 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI)) 217 return false; 218 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI)) 219 return false; 220 221 I.eraseFromParent(); 222 return true; 223 } 224 case G_ICMP: { 225 struct Instr { 226 unsigned Opcode, Def, LHS, RHS; 227 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS) 228 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){}; 229 230 bool hasImm() const { 231 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi) 232 return true; 233 return false; 234 } 235 }; 236 237 SmallVector<struct Instr, 2> Instructions; 238 unsigned ICMPReg = I.getOperand(0).getReg(); 239 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass); 240 unsigned LHS = I.getOperand(2).getReg(); 241 unsigned RHS = I.getOperand(3).getReg(); 242 CmpInst::Predicate Cond = 243 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate()); 244 245 switch (Cond) { 246 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1 247 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 248 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1); 249 break; 250 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS) 251 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS); 252 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp); 253 break; 254 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS 255 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS); 256 break; 257 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS) 258 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS); 259 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 260 break; 261 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS 262 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS); 263 break; 264 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS) 265 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS); 266 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 267 break; 268 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS 269 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS); 270 break; 271 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS) 272 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS); 273 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 274 break; 275 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS 276 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS); 277 break; 278 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS) 279 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS); 280 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1); 281 break; 282 default: 283 return false; 284 } 285 286 MachineIRBuilder B(I); 287 for (const struct Instr &Instruction : Instructions) { 288 MachineInstrBuilder MIB = B.buildInstr( 289 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS}); 290 291 if (Instruction.hasImm()) 292 MIB.addImm(Instruction.RHS); 293 else 294 MIB.addUse(Instruction.RHS); 295 296 if (!MIB.constrainAllUses(TII, TRI, RBI)) 297 return false; 298 } 299 300 I.eraseFromParent(); 301 return true; 302 } 303 default: 304 return false; 305 } 306 307 I.eraseFromParent(); 308 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 309 } 310 311 namespace llvm { 312 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM, 313 MipsSubtarget &Subtarget, 314 MipsRegisterBankInfo &RBI) { 315 return new MipsInstructionSelector(TM, Subtarget, RBI); 316 } 317 } // end namespace llvm 318