blob: 84b520261e7dbcd99a44cb12a9979e270a5723c9 [file] [log] [blame]
Petar Jovanovicfac93e22018-02-23 11:06:40 +00001//===- MipsInstructionSelector.cpp ------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Petar Jovanovicfac93e22018-02-23 11:06:40 +00006//
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"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000015#include "MipsTargetMachine.h"
Petar Jovanovic366857a2018-04-11 15:12:32 +000016#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +000017#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000018
Petar Jovanovic366857a2018-04-11 15:12:32 +000019#define DEBUG_TYPE "mips-isel"
20
Petar Jovanovicfac93e22018-02-23 11:06:40 +000021using namespace llvm;
22
23namespace {
24
Petar Jovanovic366857a2018-04-11 15:12:32 +000025#define GET_GLOBALISEL_PREDICATE_BITSET
26#include "MipsGenGlobalISel.inc"
27#undef GET_GLOBALISEL_PREDICATE_BITSET
28
Petar Jovanovicfac93e22018-02-23 11:06:40 +000029class MipsInstructionSelector : public InstructionSelector {
30public:
31 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
32 const MipsRegisterBankInfo &RBI);
33
34 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
Petar Jovanovic366857a2018-04-11 15:12:32 +000035 static const char *getName() { return DEBUG_TYPE; }
Petar Jovanovicfac93e22018-02-23 11:06:40 +000036
37private:
Petar Jovanovic366857a2018-04-11 15:12:32 +000038 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
39
40 const MipsTargetMachine &TM;
41 const MipsSubtarget &STI;
Petar Jovanovicfac93e22018-02-23 11:06:40 +000042 const MipsInstrInfo &TII;
43 const MipsRegisterInfo &TRI;
Petar Jovanovic366857a2018-04-11 15:12:32 +000044 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
Petar Jovanovicfac93e22018-02-23 11:06:40 +000053};
54
55} // end anonymous namespace
56
Petar Jovanovic366857a2018-04-11 15:12:32 +000057#define GET_GLOBALISEL_IMPL
58#include "MipsGenGlobalISel.inc"
59#undef GET_GLOBALISEL_IMPL
60
Petar Jovanovicfac93e22018-02-23 11:06:40 +000061MipsInstructionSelector::MipsInstructionSelector(
62 const MipsTargetMachine &TM, const MipsSubtarget &STI,
63 const MipsRegisterBankInfo &RBI)
Petar Jovanovic366857a2018-04-11 15:12:32 +000064 : 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
76static 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)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +000086 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
87 << " operand\n");
Petar Jovanovic366857a2018-04-11 15:12:32 +000088 return false;
89 }
90 return true;
91}
Petar Jovanovicfac93e22018-02-23 11:06:40 +000092
Petar Avramovic79df8592019-01-24 10:27:21 +000093/// Returning Opc indicates that we failed to select MIPS instruction opcode.
94static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes) {
95 if (Opc == TargetOpcode::G_STORE)
96 switch (MemSizeInBytes) {
97 case 4:
98 return Mips::SW;
Petar Avramovicc98b26d2019-02-08 14:27:23 +000099 case 2:
100 return Mips::SH;
101 case 1:
102 return Mips::SB;
Petar Avramovic79df8592019-01-24 10:27:21 +0000103 default:
104 return Opc;
105 }
106 else
Petar Avramovicc98b26d2019-02-08 14:27:23 +0000107 // Unspecified extending load is selected into zeroExtending load.
Petar Avramovic79df8592019-01-24 10:27:21 +0000108 switch (MemSizeInBytes) {
109 case 4:
110 return Mips::LW;
111 case 2:
112 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
113 case 1:
114 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
115 default:
116 return Opc;
117 }
118}
119
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000120bool MipsInstructionSelector::select(MachineInstr &I,
121 CodeGenCoverage &CoverageInfo) const {
122
Petar Jovanovic366857a2018-04-11 15:12:32 +0000123 MachineBasicBlock &MBB = *I.getParent();
124 MachineFunction &MF = *MBB.getParent();
125 MachineRegisterInfo &MRI = MF.getRegInfo();
126
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000127 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000128 if (I.isCopy())
129 return selectCopy(I, TII, MRI, TRI, RBI);
130
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000131 return true;
132 }
133
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000134 if (I.getOpcode() == Mips::G_MUL) {
135 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL))
136 .add(I.getOperand(0))
137 .add(I.getOperand(1))
138 .add(I.getOperand(2));
139 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI))
140 return false;
141 Mul->getOperand(3).setIsDead(true);
142 Mul->getOperand(4).setIsDead(true);
143
144 I.eraseFromParent();
Petar Jovanovic366857a2018-04-11 15:12:32 +0000145 return true;
146 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000147
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000148 if (selectImpl(I, CoverageInfo))
149 return true;
150
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000151 MachineInstr *MI = nullptr;
152 using namespace TargetOpcode;
153
154 switch (I.getOpcode()) {
Petar Avramovica48285a2019-03-01 07:25:44 +0000155 case G_UMULH: {
156 unsigned PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
157 MachineInstr *PseudoMULTu, *PseudoMove;
158
159 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu))
160 .addDef(PseudoMULTuReg)
161 .add(I.getOperand(1))
162 .add(I.getOperand(2));
163 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI))
164 return false;
165
166 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI))
167 .addDef(I.getOperand(0).getReg())
168 .addUse(PseudoMULTuReg);
169 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
170 return false;
171
172 I.eraseFromParent();
173 return true;
174 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000175 case G_GEP: {
176 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
177 .add(I.getOperand(0))
178 .add(I.getOperand(1))
179 .add(I.getOperand(2));
180 break;
181 }
182 case G_FRAME_INDEX: {
183 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
184 .add(I.getOperand(0))
185 .add(I.getOperand(1))
186 .addImm(0);
187 break;
188 }
Petar Avramovic5d9b8ee2019-02-14 11:39:53 +0000189 case G_BRCOND: {
190 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
191 .add(I.getOperand(0))
192 .addUse(Mips::ZERO)
193 .add(I.getOperand(1));
194 break;
195 }
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000196 case G_PHI: {
197 const unsigned DestReg = I.getOperand(0).getReg();
198 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
199 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
200
201 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
202 return false;
203
204 const TargetRegisterClass *DefRC = &Mips::GPR32RegClass;
205 I.setDesc(TII.get(TargetOpcode::PHI));
206 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
207 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000208 case G_STORE:
Petar Avramovic79df8592019-01-24 10:27:21 +0000209 case G_LOAD:
210 case G_ZEXTLOAD:
211 case G_SEXTLOAD: {
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000212 const unsigned DestReg = I.getOperand(0).getReg();
213 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
214 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
Petar Avramovic79df8592019-01-24 10:27:21 +0000215 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000216
217 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
218 return false;
219
Petar Avramovic79df8592019-01-24 10:27:21 +0000220 const unsigned NewOpc =
221 selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes);
222 if (NewOpc == I.getOpcode())
223 return false;
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000224
225 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
226 .add(I.getOperand(0))
227 .add(I.getOperand(1))
228 .addImm(0)
229 .addMemOperand(*I.memoperands_begin());
230 break;
231 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000232 case G_UDIV:
233 case G_UREM:
234 case G_SDIV:
235 case G_SREM: {
236 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
237 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
238 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
239
240 MachineInstr *PseudoDIV, *PseudoMove;
241 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
242 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
243 .addDef(HILOReg)
244 .add(I.getOperand(1))
245 .add(I.getOperand(2));
246 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
247 return false;
248
249 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
250 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
251 .addDef(I.getOperand(0).getReg())
252 .addUse(HILOReg);
253 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
254 return false;
255
256 I.eraseFromParent();
257 return true;
258 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000259 case G_SELECT: {
260 // Handle operands with pointer type.
261 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
262 .add(I.getOperand(0))
263 .add(I.getOperand(2))
264 .add(I.getOperand(1))
265 .add(I.getOperand(3));
266 break;
267 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000268 case G_CONSTANT: {
269 int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue();
270 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
271 MachineInstr *LUi, *ORi;
272
273 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
274 .addDef(LUiReg)
275 .addImm(Imm >> 16);
276
277 ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi))
278 .addDef(I.getOperand(0).getReg())
279 .addUse(LUiReg)
280 .addImm(Imm & 0xFFFF);
281
282 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
283 return false;
284 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
285 return false;
286
287 I.eraseFromParent();
288 return true;
289 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000290 case G_GLOBAL_VALUE: {
291 if (MF.getTarget().isPositionIndependent())
292 return false;
293
294 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
295 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
296 MachineInstr *LUi, *ADDiu;
297
298 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
299 .addDef(LUiReg)
300 .addGlobalAddress(GVal);
301 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
302
303 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
304 .addDef(I.getOperand(0).getReg())
305 .addUse(LUiReg)
306 .addGlobalAddress(GVal);
307 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
308
309 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
310 return false;
311 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
312 return false;
313
314 I.eraseFromParent();
315 return true;
316 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000317 case G_ICMP: {
318 struct Instr {
319 unsigned Opcode, Def, LHS, RHS;
320 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
321 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000322
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000323 bool hasImm() const {
324 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
325 return true;
326 return false;
327 }
328 };
329
330 SmallVector<struct Instr, 2> Instructions;
331 unsigned ICMPReg = I.getOperand(0).getReg();
332 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
333 unsigned LHS = I.getOperand(2).getReg();
334 unsigned RHS = I.getOperand(3).getReg();
335 CmpInst::Predicate Cond =
336 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
337
338 switch (Cond) {
339 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
340 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
341 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
342 break;
343 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
344 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
345 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
346 break;
347 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
348 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
349 break;
350 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
351 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
352 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
353 break;
354 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
355 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
356 break;
357 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
358 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
359 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
360 break;
361 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
362 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
363 break;
364 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
365 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
366 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
367 break;
368 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
369 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
370 break;
371 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
372 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
373 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
374 break;
375 default:
376 return false;
377 }
378
379 MachineIRBuilder B(I);
380 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000381 MachineInstrBuilder MIB = B.buildInstr(
382 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000383
384 if (Instruction.hasImm())
385 MIB.addImm(Instruction.RHS);
386 else
387 MIB.addUse(Instruction.RHS);
388
389 if (!MIB.constrainAllUses(TII, TRI, RBI))
390 return false;
391 }
392
393 I.eraseFromParent();
394 return true;
395 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000396 default:
397 return false;
398 }
399
400 I.eraseFromParent();
401 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000402}
403
404namespace llvm {
405InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
406 MipsSubtarget &Subtarget,
407 MipsRegisterBankInfo &RBI) {
408 return new MipsInstructionSelector(TM, Subtarget, RBI);
409}
410} // end namespace llvm