blob: 524a58b2d3e96eea44a8f33f4c05b423da136454 [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
Petar Avramovic22e99c42019-06-05 14:03:13 +000014#include "MCTargetDesc/MipsInstPrinter.h"
Petar Avramovicefcd3c02019-05-31 08:27:06 +000015#include "MipsMachineFunction.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000016#include "MipsRegisterBankInfo.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000017#include "MipsTargetMachine.h"
Petar Jovanovic366857a2018-04-11 15:12:32 +000018#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +000019#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
Petar Avramoviccaef9302019-08-08 10:21:12 +000020#include "llvm/CodeGen/MachineJumpTableInfo.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000021
Petar Jovanovic366857a2018-04-11 15:12:32 +000022#define DEBUG_TYPE "mips-isel"
23
Petar Jovanovicfac93e22018-02-23 11:06:40 +000024using namespace llvm;
25
26namespace {
27
Petar Jovanovic366857a2018-04-11 15:12:32 +000028#define GET_GLOBALISEL_PREDICATE_BITSET
29#include "MipsGenGlobalISel.inc"
30#undef GET_GLOBALISEL_PREDICATE_BITSET
31
Petar Jovanovicfac93e22018-02-23 11:06:40 +000032class MipsInstructionSelector : public InstructionSelector {
33public:
34 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
35 const MipsRegisterBankInfo &RBI);
36
Amara Emersone14c91b2019-08-13 06:26:59 +000037 bool select(MachineInstr &I) override;
Petar Jovanovic366857a2018-04-11 15:12:32 +000038 static const char *getName() { return DEBUG_TYPE; }
Petar Jovanovicfac93e22018-02-23 11:06:40 +000039
40private:
Petar Jovanovic366857a2018-04-11 15:12:32 +000041 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +000042 bool materialize32BitImm(Register DestReg, APInt Imm,
Petar Avramovic3e0da142019-03-15 07:07:50 +000043 MachineIRBuilder &B) const;
Petar Avramovica034a642019-03-25 11:38:06 +000044 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
Petar Avramovic7d0778e2019-07-10 13:18:13 +000045 const TargetRegisterClass *
46 getRegClassForTypeOnBank(unsigned OpSize, const RegisterBank &RB,
47 const RegisterBankInfo &RBI) const;
Petar Jovanovic366857a2018-04-11 15:12:32 +000048
49 const MipsTargetMachine &TM;
50 const MipsSubtarget &STI;
Petar Jovanovicfac93e22018-02-23 11:06:40 +000051 const MipsInstrInfo &TII;
52 const MipsRegisterInfo &TRI;
Petar Jovanovic366857a2018-04-11 15:12:32 +000053 const MipsRegisterBankInfo &RBI;
54
55#define GET_GLOBALISEL_PREDICATES_DECL
56#include "MipsGenGlobalISel.inc"
57#undef GET_GLOBALISEL_PREDICATES_DECL
58
59#define GET_GLOBALISEL_TEMPORARIES_DECL
60#include "MipsGenGlobalISel.inc"
61#undef GET_GLOBALISEL_TEMPORARIES_DECL
Petar Jovanovicfac93e22018-02-23 11:06:40 +000062};
63
64} // end anonymous namespace
65
Petar Jovanovic366857a2018-04-11 15:12:32 +000066#define GET_GLOBALISEL_IMPL
67#include "MipsGenGlobalISel.inc"
68#undef GET_GLOBALISEL_IMPL
69
Petar Jovanovicfac93e22018-02-23 11:06:40 +000070MipsInstructionSelector::MipsInstructionSelector(
71 const MipsTargetMachine &TM, const MipsSubtarget &STI,
72 const MipsRegisterBankInfo &RBI)
Petar Jovanovic366857a2018-04-11 15:12:32 +000073 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
74 TRI(*STI.getRegisterInfo()), RBI(RBI),
75
76#define GET_GLOBALISEL_PREDICATES_INIT
77#include "MipsGenGlobalISel.inc"
78#undef GET_GLOBALISEL_PREDICATES_INIT
79#define GET_GLOBALISEL_TEMPORARIES_INIT
80#include "MipsGenGlobalISel.inc"
81#undef GET_GLOBALISEL_TEMPORARIES_INIT
82{
83}
84
Petar Avramovica034a642019-03-25 11:38:06 +000085bool MipsInstructionSelector::selectCopy(MachineInstr &I,
86 MachineRegisterInfo &MRI) const {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +000087 Register DstReg = I.getOperand(0).getReg();
Daniel Sanders2bea69b2019-08-01 23:27:28 +000088 if (Register::isPhysicalRegister(DstReg))
Petar Jovanovic366857a2018-04-11 15:12:32 +000089 return true;
90
Petar Avramovica034a642019-03-25 11:38:06 +000091 const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI);
92 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
Petar Jovanovic366857a2018-04-11 15:12:32 +000093
Petar Avramovica034a642019-03-25 11:38:06 +000094 const TargetRegisterClass *RC = &Mips::GPR32RegClass;
95 if (RegBank->getID() == Mips::FPRBRegBankID) {
96 if (DstSize == 32)
97 RC = &Mips::FGR32RegClass;
98 else if (DstSize == 64)
99 RC = STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass;
100 else
101 llvm_unreachable("Unsupported destination size");
102 }
Petar Jovanovic366857a2018-04-11 15:12:32 +0000103 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000104 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
105 << " operand\n");
Petar Jovanovic366857a2018-04-11 15:12:32 +0000106 return false;
107 }
108 return true;
109}
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000110
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000111const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank(
112 unsigned OpSize, const RegisterBank &RB,
113 const RegisterBankInfo &RBI) const {
114 if (RB.getID() == Mips::GPRBRegBankID)
115 return &Mips::GPR32RegClass;
116
117 if (RB.getID() == Mips::FPRBRegBankID)
118 return OpSize == 32
119 ? &Mips::FGR32RegClass
120 : STI.hasMips32r6() || STI.isFP64bit() ? &Mips::FGR64RegClass
121 : &Mips::AFGR64RegClass;
122
123 llvm_unreachable("getRegClassForTypeOnBank can't find register class.");
124 return nullptr;
125}
126
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000127bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm,
Petar Avramovic3e0da142019-03-15 07:07:50 +0000128 MachineIRBuilder &B) const {
129 assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
130 // Ori zero extends immediate. Used for values with zeros in high 16 bits.
131 if (Imm.getHiBits(16).isNullValue()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000132 MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Register(Mips::ZERO)})
Petar Avramovic3e0da142019-03-15 07:07:50 +0000133 .addImm(Imm.getLoBits(16).getLimitedValue());
134 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
135 }
136 // Lui places immediate in high 16 bits and sets low 16 bits to zero.
137 if (Imm.getLoBits(16).isNullValue()) {
138 MachineInstr *Inst = B.buildInstr(Mips::LUi, {DestReg}, {})
139 .addImm(Imm.getHiBits(16).getLimitedValue());
140 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
141 }
142 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits.
143 if (Imm.isSignedIntN(16)) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000144 MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Register(Mips::ZERO)})
Petar Avramovic3e0da142019-03-15 07:07:50 +0000145 .addImm(Imm.getLoBits(16).getLimitedValue());
146 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
147 }
148 // Values that cannot be materialized with single immediate instruction.
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000149 Register LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic3e0da142019-03-15 07:07:50 +0000150 MachineInstr *LUi = B.buildInstr(Mips::LUi, {LUiReg}, {})
151 .addImm(Imm.getHiBits(16).getLimitedValue());
152 MachineInstr *ORi = B.buildInstr(Mips::ORi, {DestReg}, {LUiReg})
153 .addImm(Imm.getLoBits(16).getLimitedValue());
154 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
155 return false;
156 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
157 return false;
158 return true;
159}
160
Petar Avramovic79df8592019-01-24 10:27:21 +0000161/// Returning Opc indicates that we failed to select MIPS instruction opcode.
Petar Avramovic7b314912019-07-10 12:55:21 +0000162static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes,
163 unsigned RegBank, bool isFP64) {
164 bool isStore = Opc == TargetOpcode::G_STORE;
165 if (RegBank == Mips::GPRBRegBankID) {
166 if (isStore)
167 switch (MemSizeInBytes) {
168 case 4:
169 return Mips::SW;
170 case 2:
171 return Mips::SH;
172 case 1:
173 return Mips::SB;
174 default:
175 return Opc;
176 }
177 else
178 // Unspecified extending load is selected into zeroExtending load.
179 switch (MemSizeInBytes) {
180 case 4:
181 return Mips::LW;
182 case 2:
183 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
184 case 1:
185 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
186 default:
187 return Opc;
188 }
189 }
190
191 if (RegBank == Mips::FPRBRegBankID) {
Petar Avramovic79df8592019-01-24 10:27:21 +0000192 switch (MemSizeInBytes) {
193 case 4:
Petar Avramovic7b314912019-07-10 12:55:21 +0000194 return isStore ? Mips::SWC1 : Mips::LWC1;
195 case 8:
196 if (isFP64)
197 return isStore ? Mips::SDC164 : Mips::LDC164;
198 else
199 return isStore ? Mips::SDC1 : Mips::LDC1;
Petar Avramovic79df8592019-01-24 10:27:21 +0000200 default:
201 return Opc;
202 }
Petar Avramovic7b314912019-07-10 12:55:21 +0000203 }
204 return Opc;
Petar Avramovic79df8592019-01-24 10:27:21 +0000205}
206
Amara Emersone14c91b2019-08-13 06:26:59 +0000207bool MipsInstructionSelector::select(MachineInstr &I) {
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000208
Petar Jovanovic366857a2018-04-11 15:12:32 +0000209 MachineBasicBlock &MBB = *I.getParent();
210 MachineFunction &MF = *MBB.getParent();
211 MachineRegisterInfo &MRI = MF.getRegInfo();
212
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000213 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000214 if (I.isCopy())
Petar Avramovica034a642019-03-25 11:38:06 +0000215 return selectCopy(I, MRI);
Petar Jovanovic366857a2018-04-11 15:12:32 +0000216
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000217 return true;
218 }
219
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000220 if (I.getOpcode() == Mips::G_MUL) {
221 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL))
222 .add(I.getOperand(0))
223 .add(I.getOperand(1))
224 .add(I.getOperand(2));
225 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI))
226 return false;
227 Mul->getOperand(3).setIsDead(true);
228 Mul->getOperand(4).setIsDead(true);
229
230 I.eraseFromParent();
Petar Jovanovic366857a2018-04-11 15:12:32 +0000231 return true;
232 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000233
Amara Emersone14c91b2019-08-13 06:26:59 +0000234 if (selectImpl(I, *CoverageInfo))
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000235 return true;
236
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000237 MachineInstr *MI = nullptr;
238 using namespace TargetOpcode;
239
240 switch (I.getOpcode()) {
Petar Avramovica48285a2019-03-01 07:25:44 +0000241 case G_UMULH: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000242 Register PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovica48285a2019-03-01 07:25:44 +0000243 MachineInstr *PseudoMULTu, *PseudoMove;
244
245 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu))
246 .addDef(PseudoMULTuReg)
247 .add(I.getOperand(1))
248 .add(I.getOperand(2));
249 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI))
250 return false;
251
252 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI))
253 .addDef(I.getOperand(0).getReg())
254 .addUse(PseudoMULTuReg);
255 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
256 return false;
257
258 I.eraseFromParent();
259 return true;
260 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000261 case G_GEP: {
262 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
263 .add(I.getOperand(0))
264 .add(I.getOperand(1))
265 .add(I.getOperand(2));
266 break;
267 }
Petar Avramovicb1fc6f62019-07-26 13:08:06 +0000268 case G_INTTOPTR:
269 case G_PTRTOINT: {
270 I.setDesc(TII.get(COPY));
271 return selectCopy(I, MRI);
272 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000273 case G_FRAME_INDEX: {
274 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
275 .add(I.getOperand(0))
276 .add(I.getOperand(1))
277 .addImm(0);
278 break;
279 }
Petar Avramovic5d9b8ee2019-02-14 11:39:53 +0000280 case G_BRCOND: {
281 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
282 .add(I.getOperand(0))
283 .addUse(Mips::ZERO)
284 .add(I.getOperand(1));
285 break;
286 }
Petar Avramoviccaef9302019-08-08 10:21:12 +0000287 case G_BRJT: {
288 unsigned EntrySize =
289 MF.getJumpTableInfo()->getEntrySize(MF.getDataLayout());
290 assert(isPowerOf2_32(EntrySize) &&
291 "Non-power-of-two jump-table entry size not supported.");
292
293 Register JTIndex = MRI.createVirtualRegister(&Mips::GPR32RegClass);
294 MachineInstr *SLL = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::SLL))
295 .addDef(JTIndex)
296 .addUse(I.getOperand(2).getReg())
297 .addImm(Log2_32(EntrySize));
298 if (!constrainSelectedInstRegOperands(*SLL, TII, TRI, RBI))
299 return false;
300
301 Register DestAddress = MRI.createVirtualRegister(&Mips::GPR32RegClass);
302 MachineInstr *ADDu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
303 .addDef(DestAddress)
304 .addUse(I.getOperand(0).getReg())
305 .addUse(JTIndex);
306 if (!constrainSelectedInstRegOperands(*ADDu, TII, TRI, RBI))
307 return false;
308
309 Register Dest = MRI.createVirtualRegister(&Mips::GPR32RegClass);
310 MachineInstr *LW =
311 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
312 .addDef(Dest)
313 .addUse(DestAddress)
314 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_ABS_LO)
315 .addMemOperand(MF.getMachineMemOperand(
316 MachinePointerInfo(), MachineMemOperand::MOLoad, 4, 4));
317 if (!constrainSelectedInstRegOperands(*LW, TII, TRI, RBI))
318 return false;
319
320 if (MF.getTarget().isPositionIndependent()) {
321 Register DestTmp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
322 LW->getOperand(0).setReg(DestTmp);
323 MachineInstr *ADDu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
324 .addDef(Dest)
325 .addUse(DestTmp)
326 .addUse(MF.getInfo<MipsFunctionInfo>()
327 ->getGlobalBaseRegForGlobalISel());
328 if (!constrainSelectedInstRegOperands(*ADDu, TII, TRI, RBI))
329 return false;
330 }
331
332 MachineInstr *Branch =
333 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoIndirectBranch))
334 .addUse(Dest);
335 if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI))
336 return false;
337
338 I.eraseFromParent();
339 return true;
340 }
Petar Avramovicff6ac1e2019-09-12 11:44:36 +0000341 case G_BRINDIRECT: {
342 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoIndirectBranch))
343 .add(I.getOperand(0));
344 break;
345 }
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000346 case G_PHI: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000347 const Register DestReg = I.getOperand(0).getReg();
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000348 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
349
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000350 const TargetRegisterClass *DefRC = nullptr;
Daniel Sanders2bea69b2019-08-01 23:27:28 +0000351 if (Register::isPhysicalRegister(DestReg))
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000352 DefRC = TRI.getRegClass(DestReg);
353 else
354 DefRC = getRegClassForTypeOnBank(OpSize,
355 *RBI.getRegBank(DestReg, MRI, TRI), RBI);
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000356
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000357 I.setDesc(TII.get(TargetOpcode::PHI));
358 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
359 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000360 case G_STORE:
Petar Avramovic79df8592019-01-24 10:27:21 +0000361 case G_LOAD:
362 case G_ZEXTLOAD:
363 case G_SEXTLOAD: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000364 const Register DestReg = I.getOperand(0).getReg();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000365 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
366 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
Petar Avramovic79df8592019-01-24 10:27:21 +0000367 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000368
Petar Avramovic7b314912019-07-10 12:55:21 +0000369 if (DestRegBank == Mips::GPRBRegBankID && OpSize != 32)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000370 return false;
371
Petar Avramovic7b314912019-07-10 12:55:21 +0000372 if (DestRegBank == Mips::FPRBRegBankID && OpSize != 32 && OpSize != 64)
373 return false;
374
375 const unsigned NewOpc = selectLoadStoreOpCode(
376 I.getOpcode(), OpMemSizeInBytes, DestRegBank, STI.isFP64bit());
Petar Avramovic79df8592019-01-24 10:27:21 +0000377 if (NewOpc == I.getOpcode())
378 return false;
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000379
Petar Avramovic8a40ced2019-08-01 09:40:13 +0000380 MachineOperand BaseAddr = I.getOperand(1);
381 int64_t SignedOffset = 0;
382 // Try to fold load/store + G_GEP + G_CONSTANT
383 // %SignedOffset:(s32) = G_CONSTANT i32 16_bit_signed_immediate
384 // %Addr:(p0) = G_GEP %BaseAddr, %SignedOffset
385 // %LoadResult/%StoreSrc = load/store %Addr(p0)
386 // into:
387 // %LoadResult/%StoreSrc = NewOpc %BaseAddr(p0), 16_bit_signed_immediate
388
389 MachineInstr *Addr = MRI.getVRegDef(I.getOperand(1).getReg());
390 if (Addr->getOpcode() == G_GEP) {
391 MachineInstr *Offset = MRI.getVRegDef(Addr->getOperand(2).getReg());
392 if (Offset->getOpcode() == G_CONSTANT) {
393 APInt OffsetValue = Offset->getOperand(1).getCImm()->getValue();
394 if (OffsetValue.isSignedIntN(16)) {
395 BaseAddr = Addr->getOperand(1);
396 SignedOffset = OffsetValue.getSExtValue();
397 }
398 }
399 }
400
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000401 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
402 .add(I.getOperand(0))
Petar Avramovic8a40ced2019-08-01 09:40:13 +0000403 .add(BaseAddr)
404 .addImm(SignedOffset)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000405 .addMemOperand(*I.memoperands_begin());
406 break;
407 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000408 case G_UDIV:
409 case G_UREM:
410 case G_SDIV:
411 case G_SREM: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000412 Register HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000413 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
414 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
415
416 MachineInstr *PseudoDIV, *PseudoMove;
417 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
418 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
419 .addDef(HILOReg)
420 .add(I.getOperand(1))
421 .add(I.getOperand(2));
422 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
423 return false;
424
425 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
426 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
427 .addDef(I.getOperand(0).getReg())
428 .addUse(HILOReg);
429 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
430 return false;
431
432 I.eraseFromParent();
433 return true;
434 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000435 case G_SELECT: {
436 // Handle operands with pointer type.
437 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
438 .add(I.getOperand(0))
439 .add(I.getOperand(2))
440 .add(I.getOperand(1))
441 .add(I.getOperand(3));
442 break;
443 }
Petar Avramovic75e43a62019-09-12 11:32:38 +0000444 case G_IMPLICIT_DEF: {
445 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::IMPLICIT_DEF))
446 .add(I.getOperand(0));
447
448 // Set class based on register bank, there can be fpr and gpr implicit def.
449 MRI.setRegClass(MI->getOperand(0).getReg(),
450 getRegClassForTypeOnBank(
451 MRI.getType(I.getOperand(0).getReg()).getSizeInBits(),
452 *RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI),
453 RBI));
454 break;
455 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000456 case G_CONSTANT: {
Petar Avramovic3e0da142019-03-15 07:07:50 +0000457 MachineIRBuilder B(I);
458 if (!materialize32BitImm(I.getOperand(0).getReg(),
459 I.getOperand(1).getCImm()->getValue(), B))
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000460 return false;
461
462 I.eraseFromParent();
463 return true;
464 }
Petar Avramovic1af05df2019-03-28 16:58:12 +0000465 case G_FCONSTANT: {
466 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
467 APInt APImm = FPimm.bitcastToAPInt();
468 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
469
470 if (Size == 32) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000471 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000472 MachineIRBuilder B(I);
473 if (!materialize32BitImm(GPRReg, APImm, B))
474 return false;
475
476 MachineInstrBuilder MTC1 =
477 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
478 if (!MTC1.constrainAllUses(TII, TRI, RBI))
479 return false;
480 }
481 if (Size == 64) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000482 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
483 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000484 MachineIRBuilder B(I);
485 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
486 return false;
487 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
488 return false;
489
490 MachineInstrBuilder PairF64 = B.buildInstr(
491 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
492 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
493 if (!PairF64.constrainAllUses(TII, TRI, RBI))
494 return false;
495 }
496
497 I.eraseFromParent();
498 return true;
499 }
Petar Avramovic0a1fd352019-06-06 09:22:37 +0000500 case G_FABS: {
501 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
502 unsigned FABSOpcode =
503 Size == 32 ? Mips::FABS_S
504 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
505 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode))
506 .add(I.getOperand(0))
507 .add(I.getOperand(1));
508 break;
509 }
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000510 case G_FPTOSI: {
511 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits();
512 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
Fangrui Songddd056c2019-06-21 01:51:50 +0000513 (void)ToSize;
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000514 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
515 assert((FromSize == 32 || FromSize == 64) &&
516 "Unsupported floating point size for G_FPTOSI");
517
518 unsigned Opcode;
519 if (FromSize == 32)
520 Opcode = Mips::TRUNC_W_S;
521 else
522 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
Daniel Sanders0c476112019-08-15 19:22:08 +0000523 Register ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass);
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000524 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
525 .addDef(ResultInFPR)
526 .addUse(I.getOperand(1).getReg());
527 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI))
528 return false;
529
530 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1))
531 .addDef(I.getOperand(0).getReg())
532 .addUse(ResultInFPR);
533 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
534 return false;
535
536 I.eraseFromParent();
537 return true;
538 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000539 case G_GLOBAL_VALUE: {
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000540 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000541 if (MF.getTarget().isPositionIndependent()) {
542 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
543 .addDef(I.getOperand(0).getReg())
544 .addReg(MF.getInfo<MipsFunctionInfo>()
545 ->getGlobalBaseRegForGlobalISel())
546 .addGlobalAddress(GVal);
547 // Global Values that don't have local linkage are handled differently
548 // when they are part of call sequence. MipsCallLowering::lowerCall
549 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
550 // MO_GOT_CALL flag when Callee doesn't have local linkage.
551 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL)
552 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL);
553 else
554 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT);
555 LWGOT->addMemOperand(
556 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
557 MachineMemOperand::MOLoad, 4, 4));
558 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI))
559 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000560
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000561 if (GVal->hasLocalLinkage()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000562 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000563 LWGOT->getOperand(0).setReg(LWGOTDef);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000564
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000565 MachineInstr *ADDiu =
566 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000567 .addDef(I.getOperand(0).getReg())
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000568 .addReg(LWGOTDef)
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000569 .addGlobalAddress(GVal);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000570 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
571 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
572 return false;
573 }
574 } else {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000575 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000576
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000577 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
578 .addDef(LUiReg)
579 .addGlobalAddress(GVal);
580 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
581 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
582 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000583
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000584 MachineInstr *ADDiu =
585 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
586 .addDef(I.getOperand(0).getReg())
587 .addUse(LUiReg)
588 .addGlobalAddress(GVal);
589 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
590 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
591 return false;
592 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000593 I.eraseFromParent();
594 return true;
595 }
Petar Avramoviccaef9302019-08-08 10:21:12 +0000596 case G_JUMP_TABLE: {
597 if (MF.getTarget().isPositionIndependent()) {
598 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
599 .addDef(I.getOperand(0).getReg())
600 .addReg(MF.getInfo<MipsFunctionInfo>()
601 ->getGlobalBaseRegForGlobalISel())
602 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_GOT)
603 .addMemOperand(
604 MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
605 MachineMemOperand::MOLoad, 4, 4));
606 } else {
607 MI =
608 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
609 .addDef(I.getOperand(0).getReg())
610 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_ABS_HI);
611 }
612 break;
613 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000614 case G_ICMP: {
615 struct Instr {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000616 unsigned Opcode;
617 Register Def, LHS, RHS;
618 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000619 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000620
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000621 bool hasImm() const {
622 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
623 return true;
624 return false;
625 }
626 };
627
628 SmallVector<struct Instr, 2> Instructions;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000629 Register ICMPReg = I.getOperand(0).getReg();
630 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
631 Register LHS = I.getOperand(2).getReg();
632 Register RHS = I.getOperand(3).getReg();
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000633 CmpInst::Predicate Cond =
634 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
635
636 switch (Cond) {
637 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
638 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
639 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
640 break;
641 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
642 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
643 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
644 break;
645 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
646 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
647 break;
648 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
649 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
650 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
651 break;
652 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
653 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
654 break;
655 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
656 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
657 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
658 break;
659 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
660 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
661 break;
662 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
663 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
664 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
665 break;
666 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
667 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
668 break;
669 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
670 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
671 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
672 break;
673 default:
674 return false;
675 }
676
677 MachineIRBuilder B(I);
678 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000679 MachineInstrBuilder MIB = B.buildInstr(
680 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000681
682 if (Instruction.hasImm())
683 MIB.addImm(Instruction.RHS);
684 else
685 MIB.addUse(Instruction.RHS);
686
687 if (!MIB.constrainAllUses(TII, TRI, RBI))
688 return false;
689 }
690
691 I.eraseFromParent();
692 return true;
693 }
Petar Avramovic22e99c42019-06-05 14:03:13 +0000694 case G_FCMP: {
695 unsigned MipsFCMPCondCode;
696 bool isLogicallyNegated;
697 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
698 I.getOperand(1).getPredicate())) {
699 case CmpInst::FCMP_UNO: // Unordered
700 case CmpInst::FCMP_ORD: // Ordered (OR)
701 MipsFCMPCondCode = Mips::FCOND_UN;
702 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
703 break;
704 case CmpInst::FCMP_OEQ: // Equal
705 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
706 MipsFCMPCondCode = Mips::FCOND_OEQ;
707 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
708 break;
709 case CmpInst::FCMP_UEQ: // Unordered or Equal
710 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
711 MipsFCMPCondCode = Mips::FCOND_UEQ;
712 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
713 break;
714 case CmpInst::FCMP_OLT: // Ordered or Less Than
715 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
716 MipsFCMPCondCode = Mips::FCOND_OLT;
717 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
718 break;
719 case CmpInst::FCMP_ULT: // Unordered or Less Than
720 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
721 MipsFCMPCondCode = Mips::FCOND_ULT;
722 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
723 break;
724 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
725 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
726 MipsFCMPCondCode = Mips::FCOND_OLE;
727 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
728 break;
729 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
730 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
731 MipsFCMPCondCode = Mips::FCOND_ULE;
732 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
733 break;
734 default:
735 return false;
736 }
737
738 // Default compare result in gpr register will be `true`.
739 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
740 // using MOVF_I. When orignal predicate (Cond) is logically negated
741 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
742 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
743
Daniel Sanders0c476112019-08-15 19:22:08 +0000744 Register TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic22e99c42019-06-05 14:03:13 +0000745 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
746 .addDef(TrueInReg)
747 .addUse(Mips::ZERO)
748 .addImm(1);
749
750 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
751 unsigned FCMPOpcode =
752 Size == 32 ? Mips::FCMP_S32
753 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
754 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode))
755 .addUse(I.getOperand(2).getReg())
756 .addUse(I.getOperand(3).getReg())
757 .addImm(MipsFCMPCondCode);
758 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI))
759 return false;
760
761 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode))
762 .addDef(I.getOperand(0).getReg())
763 .addUse(Mips::ZERO)
764 .addUse(Mips::FCC0)
765 .addUse(TrueInReg);
766 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
767 return false;
768
769 I.eraseFromParent();
770 return true;
771 }
Petar Avramovica4bfc8d2019-09-05 11:20:32 +0000772 case G_FENCE: {
773 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::SYNC)).addImm(0);
774 break;
775 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000776 default:
777 return false;
778 }
779
780 I.eraseFromParent();
781 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000782}
783
784namespace llvm {
785InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
786 MipsSubtarget &Subtarget,
787 MipsRegisterBankInfo &RBI) {
788 return new MipsInstructionSelector(TM, Subtarget, RBI);
789}
790} // end namespace llvm