blob: 37d7767085a727d3b6df4746a1154c9e499ea48e [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
93bool MipsInstructionSelector::select(MachineInstr &I,
94 CodeGenCoverage &CoverageInfo) const {
95
Petar Jovanovic366857a2018-04-11 15:12:32 +000096 MachineBasicBlock &MBB = *I.getParent();
97 MachineFunction &MF = *MBB.getParent();
98 MachineRegisterInfo &MRI = MF.getRegInfo();
99
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000100 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000101 if (I.isCopy())
102 return selectCopy(I, TII, MRI, TRI, RBI);
103
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000104 return true;
105 }
106
Petar Jovanovic366857a2018-04-11 15:12:32 +0000107 if (selectImpl(I, CoverageInfo)) {
108 return true;
109 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000110
111 MachineInstr *MI = nullptr;
112 using namespace TargetOpcode;
113
114 switch (I.getOpcode()) {
115 case G_GEP: {
116 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
117 .add(I.getOperand(0))
118 .add(I.getOperand(1))
119 .add(I.getOperand(2));
120 break;
121 }
122 case G_FRAME_INDEX: {
123 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
124 .add(I.getOperand(0))
125 .add(I.getOperand(1))
126 .addImm(0);
127 break;
128 }
129 case G_STORE:
130 case G_LOAD: {
131 const unsigned DestReg = I.getOperand(0).getReg();
132 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
133 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
134
135 if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
136 return false;
137
138 const unsigned NewOpc = I.getOpcode() == G_STORE ? Mips::SW : Mips::LW;
139
140 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
141 .add(I.getOperand(0))
142 .add(I.getOperand(1))
143 .addImm(0)
144 .addMemOperand(*I.memoperands_begin());
145 break;
146 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000147 case G_UDIV:
148 case G_UREM:
149 case G_SDIV:
150 case G_SREM: {
151 unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
152 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
153 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
154
155 MachineInstr *PseudoDIV, *PseudoMove;
156 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
157 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
158 .addDef(HILOReg)
159 .add(I.getOperand(1))
160 .add(I.getOperand(2));
161 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
162 return false;
163
164 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
165 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
166 .addDef(I.getOperand(0).getReg())
167 .addUse(HILOReg);
168 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
169 return false;
170
171 I.eraseFromParent();
172 return true;
173 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000174 case G_SELECT: {
175 // Handle operands with pointer type.
176 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
177 .add(I.getOperand(0))
178 .add(I.getOperand(2))
179 .add(I.getOperand(1))
180 .add(I.getOperand(3));
181 break;
182 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000183 case G_CONSTANT: {
184 int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue();
185 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
186 MachineInstr *LUi, *ORi;
187
188 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
189 .addDef(LUiReg)
190 .addImm(Imm >> 16);
191
192 ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi))
193 .addDef(I.getOperand(0).getReg())
194 .addUse(LUiReg)
195 .addImm(Imm & 0xFFFF);
196
197 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
198 return false;
199 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
200 return false;
201
202 I.eraseFromParent();
203 return true;
204 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000205 case G_GLOBAL_VALUE: {
206 if (MF.getTarget().isPositionIndependent())
207 return false;
208
209 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
210 unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
211 MachineInstr *LUi, *ADDiu;
212
213 LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
214 .addDef(LUiReg)
215 .addGlobalAddress(GVal);
216 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
217
218 ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
219 .addDef(I.getOperand(0).getReg())
220 .addUse(LUiReg)
221 .addGlobalAddress(GVal);
222 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
223
224 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
225 return false;
226 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
227 return false;
228
229 I.eraseFromParent();
230 return true;
231 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000232 case G_ICMP: {
233 struct Instr {
234 unsigned Opcode, Def, LHS, RHS;
235 Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
236 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000237
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000238 bool hasImm() const {
239 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
240 return true;
241 return false;
242 }
243 };
244
245 SmallVector<struct Instr, 2> Instructions;
246 unsigned ICMPReg = I.getOperand(0).getReg();
247 unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
248 unsigned LHS = I.getOperand(2).getReg();
249 unsigned RHS = I.getOperand(3).getReg();
250 CmpInst::Predicate Cond =
251 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
252
253 switch (Cond) {
254 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
255 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
256 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
257 break;
258 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
259 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
260 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
261 break;
262 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
263 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
264 break;
265 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
266 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
267 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
268 break;
269 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
270 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
271 break;
272 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
273 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
274 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
275 break;
276 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
277 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
278 break;
279 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
280 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
281 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
282 break;
283 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
284 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
285 break;
286 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
287 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
288 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
289 break;
290 default:
291 return false;
292 }
293
294 MachineIRBuilder B(I);
295 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000296 MachineInstrBuilder MIB = B.buildInstr(
297 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000298
299 if (Instruction.hasImm())
300 MIB.addImm(Instruction.RHS);
301 else
302 MIB.addUse(Instruction.RHS);
303
304 if (!MIB.constrainAllUses(TII, TRI, RBI))
305 return false;
306 }
307
308 I.eraseFromParent();
309 return true;
310 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000311 default:
312 return false;
313 }
314
315 I.eraseFromParent();
316 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000317}
318
319namespace llvm {
320InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
321 MipsSubtarget &Subtarget,
322 MipsRegisterBankInfo &RBI) {
323 return new MipsInstructionSelector(TM, Subtarget, RBI);
324}
325} // end namespace llvm