blob: 36aea2983591a855bccc8055ea02b8eb5e7d08c1 [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;
Petar Avramovic3e0da142019-03-15 07:07:50 +000039 bool materialize32BitImm(unsigned DestReg, APInt Imm,
40 MachineIRBuilder &B) const;
Petar Jovanovic366857a2018-04-11 15:12:32 +000041
42 const MipsTargetMachine &TM;
43 const MipsSubtarget &STI;
Petar Jovanovicfac93e22018-02-23 11:06:40 +000044 const MipsInstrInfo &TII;
45 const MipsRegisterInfo &TRI;
Petar Jovanovic366857a2018-04-11 15:12:32 +000046 const MipsRegisterBankInfo &RBI;
47
48#define GET_GLOBALISEL_PREDICATES_DECL
49#include "MipsGenGlobalISel.inc"
50#undef GET_GLOBALISEL_PREDICATES_DECL
51
52#define GET_GLOBALISEL_TEMPORARIES_DECL
53#include "MipsGenGlobalISel.inc"
54#undef GET_GLOBALISEL_TEMPORARIES_DECL
Petar Jovanovicfac93e22018-02-23 11:06:40 +000055};
56
57} // end anonymous namespace
58
Petar Jovanovic366857a2018-04-11 15:12:32 +000059#define GET_GLOBALISEL_IMPL
60#include "MipsGenGlobalISel.inc"
61#undef GET_GLOBALISEL_IMPL
62
Petar Jovanovicfac93e22018-02-23 11:06:40 +000063MipsInstructionSelector::MipsInstructionSelector(
64 const MipsTargetMachine &TM, const MipsSubtarget &STI,
65 const MipsRegisterBankInfo &RBI)
Petar Jovanovic366857a2018-04-11 15:12:32 +000066 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
67 TRI(*STI.getRegisterInfo()), RBI(RBI),
68
69#define GET_GLOBALISEL_PREDICATES_INIT
70#include "MipsGenGlobalISel.inc"
71#undef GET_GLOBALISEL_PREDICATES_INIT
72#define GET_GLOBALISEL_TEMPORARIES_INIT
73#include "MipsGenGlobalISel.inc"
74#undef GET_GLOBALISEL_TEMPORARIES_INIT
75{
76}
77
78static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
79 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
80 const RegisterBankInfo &RBI) {
81 unsigned DstReg = I.getOperand(0).getReg();
82 if (TargetRegisterInfo::isPhysicalRegister(DstReg))
83 return true;
84
85 const TargetRegisterClass *RC = &Mips::GPR32RegClass;
86
87 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +000088 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
89 << " operand\n");
Petar Jovanovic366857a2018-04-11 15:12:32 +000090 return false;
91 }
92 return true;
93}
Petar Jovanovicfac93e22018-02-23 11:06:40 +000094
Petar Avramovic3e0da142019-03-15 07:07:50 +000095bool MipsInstructionSelector::materialize32BitImm(unsigned DestReg, APInt Imm,
96 MachineIRBuilder &B) const {
97 assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
98 // Ori zero extends immediate. Used for values with zeros in high 16 bits.
99 if (Imm.getHiBits(16).isNullValue()) {
100 MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Mips::ZERO})
101 .addImm(Imm.getLoBits(16).getLimitedValue());
102 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
103 }
104 // Lui places immediate in high 16 bits and sets low 16 bits to zero.
105 if (Imm.getLoBits(16).isNullValue()) {
106 MachineInstr *Inst = B.buildInstr(Mips::LUi, {DestReg}, {})
107 .addImm(Imm.getHiBits(16).getLimitedValue());
108 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
109 }
110 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits.
111 if (Imm.isSignedIntN(16)) {
112 MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Mips::ZERO})
113 .addImm(Imm.getLoBits(16).getLimitedValue());
114 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
115 }
116 // Values that cannot be materialized with single immediate instruction.
117 unsigned LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass);
118 MachineInstr *LUi = B.buildInstr(Mips::LUi, {LUiReg}, {})
119 .addImm(Imm.getHiBits(16).getLimitedValue());
120 MachineInstr *ORi = B.buildInstr(Mips::ORi, {DestReg}, {LUiReg})
121 .addImm(Imm.getLoBits(16).getLimitedValue());
122 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
123 return false;
124 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
125 return false;
126 return true;
127}
128
Petar Avramovic79df8592019-01-24 10:27:21 +0000129/// Returning Opc indicates that we failed to select MIPS instruction opcode.
130static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes) {
131 if (Opc == TargetOpcode::G_STORE)
132 switch (MemSizeInBytes) {
133 case 4:
134 return Mips::SW;
Petar Avramovicc98b26d2019-02-08 14:27:23 +0000135 case 2:
136 return Mips::SH;
137 case 1:
138 return Mips::SB;
Petar Avramovic79df8592019-01-24 10:27:21 +0000139 default:
140 return Opc;
141 }
142 else
Petar Avramovicc98b26d2019-02-08 14:27:23 +0000143 // Unspecified extending load is selected into zeroExtending load.
Petar Avramovic79df8592019-01-24 10:27:21 +0000144 switch (MemSizeInBytes) {
145 case 4:
146 return Mips::LW;
147 case 2:
148 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
149 case 1:
150 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
151 default:
152 return Opc;
153 }
154}
155
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000156bool MipsInstructionSelector::select(MachineInstr &I,
157 CodeGenCoverage &CoverageInfo) const {
158
Petar Jovanovic366857a2018-04-11 15:12:32 +0000159 MachineBasicBlock &MBB = *I.getParent();
160 MachineFunction &MF = *MBB.getParent();
161 MachineRegisterInfo &MRI = MF.getRegInfo();
162
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000163 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000164 if (I.isCopy())
165 return selectCopy(I, TII, MRI, TRI, RBI);
166
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000167 return true;
168 }
169
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000170 if (I.getOpcode() == Mips::G_MUL) {
171 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL))
172 .add(I.getOperand(0))
173 .add(I.getOperand(1))
174 .add(I.getOperand(2));
175 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI))
176 return false;
177 Mul->getOperand(3).setIsDead(true);
178 Mul->getOperand(4).setIsDead(true);
179
180 I.eraseFromParent();
Petar Jovanovic366857a2018-04-11 15:12:32 +0000181 return true;
182 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000183
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000184 if (selectImpl(I, CoverageInfo))
185 return true;
186
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000187 MachineInstr *MI = nullptr;
188 using namespace TargetOpcode;
189
190 switch (I.getOpcode()) {
Petar Avramovica48285a2019-03-01 07:25:44 +0000191 case G_UMULH: {
192 unsigned PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
193 MachineInstr *PseudoMULTu, *PseudoMove;
194
195 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu))
196 .addDef(PseudoMULTuReg)
197 .add(I.getOperand(1))
198 .add(I.getOperand(2));
199 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI))
200 return false;
201
202 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI))
203 .addDef(I.getOperand(0).getReg())
204 .addUse(PseudoMULTuReg);
205 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
206 return false;
207
208 I.eraseFromParent();
209 return true;
210 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000211 case G_GEP: {
212 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
213 .add(I.getOperand(0))
214 .add(I.getOperand(1))
215 .add(I.getOperand(2));
216 break;
217 }
218 case G_FRAME_INDEX: {
219 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
220 .add(I.getOperand(0))
221 .add(I.getOperand(1))
222 .addImm(0);
223 break;
224 }
Petar Avramovic5d9b8ee2019-02-14 11:39:53 +0000225 case G_BRCOND: {
226 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
227 .add(I.getOperand(0))
228 .addUse(Mips::ZERO)
229 .add(I.getOperand(1));
230 break;
231 }
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000232 case G_PHI: {
233 const unsigned DestReg = I.getOperand(0).getReg();
234 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
235 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
236
237 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
238 return false;
239
240 const TargetRegisterClass *DefRC = &Mips::GPR32RegClass;
241 I.setDesc(TII.get(TargetOpcode::PHI));
242 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
243 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000244 case G_STORE:
Petar Avramovic79df8592019-01-24 10:27:21 +0000245 case G_LOAD:
246 case G_ZEXTLOAD:
247 case G_SEXTLOAD: {
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000248 const unsigned DestReg = I.getOperand(0).getReg();
249 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
250 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
Petar Avramovic79df8592019-01-24 10:27:21 +0000251 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000252
253 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
254 return false;
255
Petar Avramovic79df8592019-01-24 10:27:21 +0000256 const unsigned NewOpc =
257 selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes);
258 if (NewOpc == I.getOpcode())
259 return false;
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000260
261 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
262 .add(I.getOperand(0))
263 .add(I.getOperand(1))
264 .addImm(0)
265 .addMemOperand(*I.memoperands_begin());
266 break;
267 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000268 case G_UDIV:
269 case G_UREM:
270 case G_SDIV:
271 case G_SREM: {
272 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
273 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
274 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
275
276 MachineInstr *PseudoDIV, *PseudoMove;
277 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
278 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
279 .addDef(HILOReg)
280 .add(I.getOperand(1))
281 .add(I.getOperand(2));
282 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
283 return false;
284
285 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
286 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
287 .addDef(I.getOperand(0).getReg())
288 .addUse(HILOReg);
289 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
290 return false;
291
292 I.eraseFromParent();
293 return true;
294 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000295 case G_SELECT: {
296 // Handle operands with pointer type.
297 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
298 .add(I.getOperand(0))
299 .add(I.getOperand(2))
300 .add(I.getOperand(1))
301 .add(I.getOperand(3));
302 break;
303 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000304 case G_CONSTANT: {
Petar Avramovic3e0da142019-03-15 07:07:50 +0000305 MachineIRBuilder B(I);
306 if (!materialize32BitImm(I.getOperand(0).getReg(),
307 I.getOperand(1).getCImm()->getValue(), B))
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000308 return false;
309
310 I.eraseFromParent();
311 return true;
312 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000313 case G_GLOBAL_VALUE: {
314 if (MF.getTarget().isPositionIndependent())
315 return false;
316
317 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
318 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
319 MachineInstr *LUi, *ADDiu;
320
321 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
322 .addDef(LUiReg)
323 .addGlobalAddress(GVal);
324 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
325
326 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
327 .addDef(I.getOperand(0).getReg())
328 .addUse(LUiReg)
329 .addGlobalAddress(GVal);
330 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
331
332 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
333 return false;
334 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
335 return false;
336
337 I.eraseFromParent();
338 return true;
339 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000340 case G_ICMP: {
341 struct Instr {
342 unsigned Opcode, Def, LHS, RHS;
343 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
344 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000345
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000346 bool hasImm() const {
347 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
348 return true;
349 return false;
350 }
351 };
352
353 SmallVector<struct Instr, 2> Instructions;
354 unsigned ICMPReg = I.getOperand(0).getReg();
355 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
356 unsigned LHS = I.getOperand(2).getReg();
357 unsigned RHS = I.getOperand(3).getReg();
358 CmpInst::Predicate Cond =
359 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
360
361 switch (Cond) {
362 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
363 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
364 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
365 break;
366 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
367 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
368 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
369 break;
370 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
371 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
372 break;
373 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
374 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
375 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
376 break;
377 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
378 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
379 break;
380 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
381 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
382 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
383 break;
384 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
385 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
386 break;
387 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
388 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
389 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
390 break;
391 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
392 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
393 break;
394 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
395 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
396 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
397 break;
398 default:
399 return false;
400 }
401
402 MachineIRBuilder B(I);
403 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000404 MachineInstrBuilder MIB = B.buildInstr(
405 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000406
407 if (Instruction.hasImm())
408 MIB.addImm(Instruction.RHS);
409 else
410 MIB.addUse(Instruction.RHS);
411
412 if (!MIB.constrainAllUses(TII, TRI, RBI))
413 return false;
414 }
415
416 I.eraseFromParent();
417 return true;
418 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000419 default:
420 return false;
421 }
422
423 I.eraseFromParent();
424 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000425}
426
427namespace llvm {
428InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
429 MipsSubtarget &Subtarget,
430 MipsRegisterBankInfo &RBI) {
431 return new MipsInstructionSelector(TM, Subtarget, RBI);
432}
433} // end namespace llvm