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;
getName()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
MipsInstructionSelector(const MipsTargetMachine & TM,const MipsSubtarget & STI,const MipsRegisterBankInfo & RBI)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
selectCopy(MachineInstr & I,const TargetInstrInfo & TII,MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,const RegisterBankInfo & RBI)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
select(MachineInstr & I,CodeGenCoverage & CoverageInfo) const94 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 {
createMipsInstructionSelector(const MipsTargetMachine & TM,MipsSubtarget & Subtarget,MipsRegisterBankInfo & RBI)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