blob: 4964ca9cbe15048f4553029f149461a0dae96e0b [file] [log] [blame]
Petar Jovanovicfac93e22018-02-23 11:06:40 +00001//===- 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"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000016#include "MipsTargetMachine.h"
Petar Jovanovic366857a2018-04-11 15:12:32 +000017#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +000018#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000019
Petar Jovanovic366857a2018-04-11 15:12:32 +000020#define DEBUG_TYPE "mips-isel"
21
Petar Jovanovicfac93e22018-02-23 11:06:40 +000022using namespace llvm;
23
24namespace {
25
Petar Jovanovic366857a2018-04-11 15:12:32 +000026#define GET_GLOBALISEL_PREDICATE_BITSET
27#include "MipsGenGlobalISel.inc"
28#undef GET_GLOBALISEL_PREDICATE_BITSET
29
Petar Jovanovicfac93e22018-02-23 11:06:40 +000030class MipsInstructionSelector : public InstructionSelector {
31public:
32 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
33 const MipsRegisterBankInfo &RBI);
34
35 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
Petar Jovanovic366857a2018-04-11 15:12:32 +000036 static const char *getName() { return DEBUG_TYPE; }
Petar Jovanovicfac93e22018-02-23 11:06:40 +000037
38private:
Petar Jovanovic366857a2018-04-11 15:12:32 +000039 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
40
41 const MipsTargetMachine &TM;
42 const MipsSubtarget &STI;
Petar Jovanovicfac93e22018-02-23 11:06:40 +000043 const MipsInstrInfo &TII;
44 const MipsRegisterInfo &TRI;
Petar Jovanovic366857a2018-04-11 15:12:32 +000045 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
Petar Jovanovicfac93e22018-02-23 11:06:40 +000054};
55
56} // end anonymous namespace
57
Petar Jovanovic366857a2018-04-11 15:12:32 +000058#define GET_GLOBALISEL_IMPL
59#include "MipsGenGlobalISel.inc"
60#undef GET_GLOBALISEL_IMPL
61
Petar Jovanovicfac93e22018-02-23 11:06:40 +000062MipsInstructionSelector::MipsInstructionSelector(
63 const MipsTargetMachine &TM, const MipsSubtarget &STI,
64 const MipsRegisterBankInfo &RBI)
Petar Jovanovic366857a2018-04-11 15:12:32 +000065 : 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
77static 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)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +000087 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
88 << " operand\n");
Petar Jovanovic366857a2018-04-11 15:12:32 +000089 return false;
90 }
91 return true;
92}
Petar Jovanovicfac93e22018-02-23 11:06:40 +000093
94bool MipsInstructionSelector::select(MachineInstr &I,
95 CodeGenCoverage &CoverageInfo) const {
96
Petar Jovanovic366857a2018-04-11 15:12:32 +000097 MachineBasicBlock &MBB = *I.getParent();
98 MachineFunction &MF = *MBB.getParent();
99 MachineRegisterInfo &MRI = MF.getRegInfo();
100
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000101 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000102 if (I.isCopy())
103 return selectCopy(I, TII, MRI, TRI, RBI);
104
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000105 return true;
106 }
107
Petar Jovanovic366857a2018-04-11 15:12:32 +0000108 if (selectImpl(I, CoverageInfo)) {
109 return true;
110 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000111
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 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000148 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 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000175 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 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000197 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 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000224 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){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000229
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000230 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) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000288 MachineInstrBuilder MIB = B.buildInstr(
289 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000290
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 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000303 default:
304 return false;
305 }
306
307 I.eraseFromParent();
308 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000309}
310
311namespace llvm {
312InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
313 MipsSubtarget &Subtarget,
314 MipsRegisterBankInfo &RBI) {
315 return new MipsInstructionSelector(TM, Subtarget, RBI);
316}
317} // end namespace llvm