blob: c5af363d8c0e7d6c49491322550ee8c5e06e243f [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 Avramovic14c7ecf2019-02-14 12:36:19 +0000341 case G_PHI: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000342 const Register DestReg = I.getOperand(0).getReg();
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000343 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
344
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000345 const TargetRegisterClass *DefRC = nullptr;
Daniel Sanders2bea69b2019-08-01 23:27:28 +0000346 if (Register::isPhysicalRegister(DestReg))
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000347 DefRC = TRI.getRegClass(DestReg);
348 else
349 DefRC = getRegClassForTypeOnBank(OpSize,
350 *RBI.getRegBank(DestReg, MRI, TRI), RBI);
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000351
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000352 I.setDesc(TII.get(TargetOpcode::PHI));
353 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
354 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000355 case G_STORE:
Petar Avramovic79df8592019-01-24 10:27:21 +0000356 case G_LOAD:
357 case G_ZEXTLOAD:
358 case G_SEXTLOAD: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000359 const Register DestReg = I.getOperand(0).getReg();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000360 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
361 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
Petar Avramovic79df8592019-01-24 10:27:21 +0000362 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000363
Petar Avramovic7b314912019-07-10 12:55:21 +0000364 if (DestRegBank == Mips::GPRBRegBankID && OpSize != 32)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000365 return false;
366
Petar Avramovic7b314912019-07-10 12:55:21 +0000367 if (DestRegBank == Mips::FPRBRegBankID && OpSize != 32 && OpSize != 64)
368 return false;
369
370 const unsigned NewOpc = selectLoadStoreOpCode(
371 I.getOpcode(), OpMemSizeInBytes, DestRegBank, STI.isFP64bit());
Petar Avramovic79df8592019-01-24 10:27:21 +0000372 if (NewOpc == I.getOpcode())
373 return false;
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000374
Petar Avramovic8a40ced2019-08-01 09:40:13 +0000375 MachineOperand BaseAddr = I.getOperand(1);
376 int64_t SignedOffset = 0;
377 // Try to fold load/store + G_GEP + G_CONSTANT
378 // %SignedOffset:(s32) = G_CONSTANT i32 16_bit_signed_immediate
379 // %Addr:(p0) = G_GEP %BaseAddr, %SignedOffset
380 // %LoadResult/%StoreSrc = load/store %Addr(p0)
381 // into:
382 // %LoadResult/%StoreSrc = NewOpc %BaseAddr(p0), 16_bit_signed_immediate
383
384 MachineInstr *Addr = MRI.getVRegDef(I.getOperand(1).getReg());
385 if (Addr->getOpcode() == G_GEP) {
386 MachineInstr *Offset = MRI.getVRegDef(Addr->getOperand(2).getReg());
387 if (Offset->getOpcode() == G_CONSTANT) {
388 APInt OffsetValue = Offset->getOperand(1).getCImm()->getValue();
389 if (OffsetValue.isSignedIntN(16)) {
390 BaseAddr = Addr->getOperand(1);
391 SignedOffset = OffsetValue.getSExtValue();
392 }
393 }
394 }
395
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000396 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
397 .add(I.getOperand(0))
Petar Avramovic8a40ced2019-08-01 09:40:13 +0000398 .add(BaseAddr)
399 .addImm(SignedOffset)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000400 .addMemOperand(*I.memoperands_begin());
401 break;
402 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000403 case G_UDIV:
404 case G_UREM:
405 case G_SDIV:
406 case G_SREM: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000407 Register HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000408 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
409 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
410
411 MachineInstr *PseudoDIV, *PseudoMove;
412 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
413 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
414 .addDef(HILOReg)
415 .add(I.getOperand(1))
416 .add(I.getOperand(2));
417 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
418 return false;
419
420 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
421 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
422 .addDef(I.getOperand(0).getReg())
423 .addUse(HILOReg);
424 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
425 return false;
426
427 I.eraseFromParent();
428 return true;
429 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000430 case G_SELECT: {
431 // Handle operands with pointer type.
432 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
433 .add(I.getOperand(0))
434 .add(I.getOperand(2))
435 .add(I.getOperand(1))
436 .add(I.getOperand(3));
437 break;
438 }
Petar Avramovic75e43a62019-09-12 11:32:38 +0000439 case G_IMPLICIT_DEF: {
440 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::IMPLICIT_DEF))
441 .add(I.getOperand(0));
442
443 // Set class based on register bank, there can be fpr and gpr implicit def.
444 MRI.setRegClass(MI->getOperand(0).getReg(),
445 getRegClassForTypeOnBank(
446 MRI.getType(I.getOperand(0).getReg()).getSizeInBits(),
447 *RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI),
448 RBI));
449 break;
450 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000451 case G_CONSTANT: {
Petar Avramovic3e0da142019-03-15 07:07:50 +0000452 MachineIRBuilder B(I);
453 if (!materialize32BitImm(I.getOperand(0).getReg(),
454 I.getOperand(1).getCImm()->getValue(), B))
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000455 return false;
456
457 I.eraseFromParent();
458 return true;
459 }
Petar Avramovic1af05df2019-03-28 16:58:12 +0000460 case G_FCONSTANT: {
461 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
462 APInt APImm = FPimm.bitcastToAPInt();
463 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
464
465 if (Size == 32) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000466 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000467 MachineIRBuilder B(I);
468 if (!materialize32BitImm(GPRReg, APImm, B))
469 return false;
470
471 MachineInstrBuilder MTC1 =
472 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
473 if (!MTC1.constrainAllUses(TII, TRI, RBI))
474 return false;
475 }
476 if (Size == 64) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000477 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
478 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000479 MachineIRBuilder B(I);
480 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
481 return false;
482 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
483 return false;
484
485 MachineInstrBuilder PairF64 = B.buildInstr(
486 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
487 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
488 if (!PairF64.constrainAllUses(TII, TRI, RBI))
489 return false;
490 }
491
492 I.eraseFromParent();
493 return true;
494 }
Petar Avramovic0a1fd352019-06-06 09:22:37 +0000495 case G_FABS: {
496 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
497 unsigned FABSOpcode =
498 Size == 32 ? Mips::FABS_S
499 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
500 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode))
501 .add(I.getOperand(0))
502 .add(I.getOperand(1));
503 break;
504 }
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000505 case G_FPTOSI: {
506 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits();
507 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
Fangrui Songddd056c2019-06-21 01:51:50 +0000508 (void)ToSize;
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000509 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
510 assert((FromSize == 32 || FromSize == 64) &&
511 "Unsupported floating point size for G_FPTOSI");
512
513 unsigned Opcode;
514 if (FromSize == 32)
515 Opcode = Mips::TRUNC_W_S;
516 else
517 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
Daniel Sanders0c476112019-08-15 19:22:08 +0000518 Register ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass);
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000519 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
520 .addDef(ResultInFPR)
521 .addUse(I.getOperand(1).getReg());
522 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI))
523 return false;
524
525 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1))
526 .addDef(I.getOperand(0).getReg())
527 .addUse(ResultInFPR);
528 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
529 return false;
530
531 I.eraseFromParent();
532 return true;
533 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000534 case G_GLOBAL_VALUE: {
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000535 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000536 if (MF.getTarget().isPositionIndependent()) {
537 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
538 .addDef(I.getOperand(0).getReg())
539 .addReg(MF.getInfo<MipsFunctionInfo>()
540 ->getGlobalBaseRegForGlobalISel())
541 .addGlobalAddress(GVal);
542 // Global Values that don't have local linkage are handled differently
543 // when they are part of call sequence. MipsCallLowering::lowerCall
544 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
545 // MO_GOT_CALL flag when Callee doesn't have local linkage.
546 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL)
547 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL);
548 else
549 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT);
550 LWGOT->addMemOperand(
551 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
552 MachineMemOperand::MOLoad, 4, 4));
553 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI))
554 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000555
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000556 if (GVal->hasLocalLinkage()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000557 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000558 LWGOT->getOperand(0).setReg(LWGOTDef);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000559
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000560 MachineInstr *ADDiu =
561 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000562 .addDef(I.getOperand(0).getReg())
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000563 .addReg(LWGOTDef)
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000564 .addGlobalAddress(GVal);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000565 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
566 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
567 return false;
568 }
569 } else {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000570 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000571
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000572 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
573 .addDef(LUiReg)
574 .addGlobalAddress(GVal);
575 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
576 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
577 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000578
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000579 MachineInstr *ADDiu =
580 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
581 .addDef(I.getOperand(0).getReg())
582 .addUse(LUiReg)
583 .addGlobalAddress(GVal);
584 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
585 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
586 return false;
587 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000588 I.eraseFromParent();
589 return true;
590 }
Petar Avramoviccaef9302019-08-08 10:21:12 +0000591 case G_JUMP_TABLE: {
592 if (MF.getTarget().isPositionIndependent()) {
593 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
594 .addDef(I.getOperand(0).getReg())
595 .addReg(MF.getInfo<MipsFunctionInfo>()
596 ->getGlobalBaseRegForGlobalISel())
597 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_GOT)
598 .addMemOperand(
599 MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
600 MachineMemOperand::MOLoad, 4, 4));
601 } else {
602 MI =
603 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
604 .addDef(I.getOperand(0).getReg())
605 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_ABS_HI);
606 }
607 break;
608 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000609 case G_ICMP: {
610 struct Instr {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000611 unsigned Opcode;
612 Register Def, LHS, RHS;
613 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000614 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000615
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000616 bool hasImm() const {
617 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
618 return true;
619 return false;
620 }
621 };
622
623 SmallVector<struct Instr, 2> Instructions;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000624 Register ICMPReg = I.getOperand(0).getReg();
625 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
626 Register LHS = I.getOperand(2).getReg();
627 Register RHS = I.getOperand(3).getReg();
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000628 CmpInst::Predicate Cond =
629 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
630
631 switch (Cond) {
632 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
633 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
634 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
635 break;
636 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
637 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
638 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
639 break;
640 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
641 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
642 break;
643 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
644 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
645 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
646 break;
647 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
648 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
649 break;
650 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
651 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
652 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
653 break;
654 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
655 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
656 break;
657 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
658 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
659 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
660 break;
661 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
662 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
663 break;
664 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
665 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
666 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
667 break;
668 default:
669 return false;
670 }
671
672 MachineIRBuilder B(I);
673 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000674 MachineInstrBuilder MIB = B.buildInstr(
675 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000676
677 if (Instruction.hasImm())
678 MIB.addImm(Instruction.RHS);
679 else
680 MIB.addUse(Instruction.RHS);
681
682 if (!MIB.constrainAllUses(TII, TRI, RBI))
683 return false;
684 }
685
686 I.eraseFromParent();
687 return true;
688 }
Petar Avramovic22e99c42019-06-05 14:03:13 +0000689 case G_FCMP: {
690 unsigned MipsFCMPCondCode;
691 bool isLogicallyNegated;
692 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
693 I.getOperand(1).getPredicate())) {
694 case CmpInst::FCMP_UNO: // Unordered
695 case CmpInst::FCMP_ORD: // Ordered (OR)
696 MipsFCMPCondCode = Mips::FCOND_UN;
697 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
698 break;
699 case CmpInst::FCMP_OEQ: // Equal
700 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
701 MipsFCMPCondCode = Mips::FCOND_OEQ;
702 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
703 break;
704 case CmpInst::FCMP_UEQ: // Unordered or Equal
705 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
706 MipsFCMPCondCode = Mips::FCOND_UEQ;
707 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
708 break;
709 case CmpInst::FCMP_OLT: // Ordered or Less Than
710 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
711 MipsFCMPCondCode = Mips::FCOND_OLT;
712 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
713 break;
714 case CmpInst::FCMP_ULT: // Unordered or Less Than
715 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
716 MipsFCMPCondCode = Mips::FCOND_ULT;
717 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
718 break;
719 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
720 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
721 MipsFCMPCondCode = Mips::FCOND_OLE;
722 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
723 break;
724 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
725 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
726 MipsFCMPCondCode = Mips::FCOND_ULE;
727 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
728 break;
729 default:
730 return false;
731 }
732
733 // Default compare result in gpr register will be `true`.
734 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
735 // using MOVF_I. When orignal predicate (Cond) is logically negated
736 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
737 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
738
Daniel Sanders0c476112019-08-15 19:22:08 +0000739 Register TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic22e99c42019-06-05 14:03:13 +0000740 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
741 .addDef(TrueInReg)
742 .addUse(Mips::ZERO)
743 .addImm(1);
744
745 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
746 unsigned FCMPOpcode =
747 Size == 32 ? Mips::FCMP_S32
748 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
749 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode))
750 .addUse(I.getOperand(2).getReg())
751 .addUse(I.getOperand(3).getReg())
752 .addImm(MipsFCMPCondCode);
753 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI))
754 return false;
755
756 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode))
757 .addDef(I.getOperand(0).getReg())
758 .addUse(Mips::ZERO)
759 .addUse(Mips::FCC0)
760 .addUse(TrueInReg);
761 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
762 return false;
763
764 I.eraseFromParent();
765 return true;
766 }
Petar Avramovica4bfc8d2019-09-05 11:20:32 +0000767 case G_FENCE: {
768 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::SYNC)).addImm(0);
769 break;
770 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000771 default:
772 return false;
773 }
774
775 I.eraseFromParent();
776 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000777}
778
779namespace llvm {
780InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
781 MipsSubtarget &Subtarget,
782 MipsRegisterBankInfo &RBI) {
783 return new MipsInstructionSelector(TM, Subtarget, RBI);
784}
785} // end namespace llvm