blob: 2ac8b0fd1da4ebfe8d7297ca1b15fcdec769d292 [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
37 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const 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
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000207bool MipsInstructionSelector::select(MachineInstr &I,
208 CodeGenCoverage &CoverageInfo) const {
209
Petar Jovanovic366857a2018-04-11 15:12:32 +0000210 MachineBasicBlock &MBB = *I.getParent();
211 MachineFunction &MF = *MBB.getParent();
212 MachineRegisterInfo &MRI = MF.getRegInfo();
213
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000214 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000215 if (I.isCopy())
Petar Avramovica034a642019-03-25 11:38:06 +0000216 return selectCopy(I, MRI);
Petar Jovanovic366857a2018-04-11 15:12:32 +0000217
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000218 return true;
219 }
220
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000221 if (I.getOpcode() == Mips::G_MUL) {
222 MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL))
223 .add(I.getOperand(0))
224 .add(I.getOperand(1))
225 .add(I.getOperand(2));
226 if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI))
227 return false;
228 Mul->getOperand(3).setIsDead(true);
229 Mul->getOperand(4).setIsDead(true);
230
231 I.eraseFromParent();
Petar Jovanovic366857a2018-04-11 15:12:32 +0000232 return true;
233 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000234
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000235 if (selectImpl(I, CoverageInfo))
236 return true;
237
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000238 MachineInstr *MI = nullptr;
239 using namespace TargetOpcode;
240
241 switch (I.getOpcode()) {
Petar Avramovica48285a2019-03-01 07:25:44 +0000242 case G_UMULH: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000243 Register PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovica48285a2019-03-01 07:25:44 +0000244 MachineInstr *PseudoMULTu, *PseudoMove;
245
246 PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu))
247 .addDef(PseudoMULTuReg)
248 .add(I.getOperand(1))
249 .add(I.getOperand(2));
250 if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI))
251 return false;
252
253 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI))
254 .addDef(I.getOperand(0).getReg())
255 .addUse(PseudoMULTuReg);
256 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
257 return false;
258
259 I.eraseFromParent();
260 return true;
261 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000262 case G_GEP: {
263 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
264 .add(I.getOperand(0))
265 .add(I.getOperand(1))
266 .add(I.getOperand(2));
267 break;
268 }
Petar Avramovicb1fc6f62019-07-26 13:08:06 +0000269 case G_INTTOPTR:
270 case G_PTRTOINT: {
271 I.setDesc(TII.get(COPY));
272 return selectCopy(I, MRI);
273 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000274 case G_FRAME_INDEX: {
275 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
276 .add(I.getOperand(0))
277 .add(I.getOperand(1))
278 .addImm(0);
279 break;
280 }
Petar Avramovic5d9b8ee2019-02-14 11:39:53 +0000281 case G_BRCOND: {
282 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
283 .add(I.getOperand(0))
284 .addUse(Mips::ZERO)
285 .add(I.getOperand(1));
286 break;
287 }
Petar Avramoviccaef9302019-08-08 10:21:12 +0000288 case G_BRJT: {
289 unsigned EntrySize =
290 MF.getJumpTableInfo()->getEntrySize(MF.getDataLayout());
291 assert(isPowerOf2_32(EntrySize) &&
292 "Non-power-of-two jump-table entry size not supported.");
293
294 Register JTIndex = MRI.createVirtualRegister(&Mips::GPR32RegClass);
295 MachineInstr *SLL = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::SLL))
296 .addDef(JTIndex)
297 .addUse(I.getOperand(2).getReg())
298 .addImm(Log2_32(EntrySize));
299 if (!constrainSelectedInstRegOperands(*SLL, TII, TRI, RBI))
300 return false;
301
302 Register DestAddress = MRI.createVirtualRegister(&Mips::GPR32RegClass);
303 MachineInstr *ADDu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
304 .addDef(DestAddress)
305 .addUse(I.getOperand(0).getReg())
306 .addUse(JTIndex);
307 if (!constrainSelectedInstRegOperands(*ADDu, TII, TRI, RBI))
308 return false;
309
310 Register Dest = MRI.createVirtualRegister(&Mips::GPR32RegClass);
311 MachineInstr *LW =
312 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
313 .addDef(Dest)
314 .addUse(DestAddress)
315 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_ABS_LO)
316 .addMemOperand(MF.getMachineMemOperand(
317 MachinePointerInfo(), MachineMemOperand::MOLoad, 4, 4));
318 if (!constrainSelectedInstRegOperands(*LW, TII, TRI, RBI))
319 return false;
320
321 if (MF.getTarget().isPositionIndependent()) {
322 Register DestTmp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
323 LW->getOperand(0).setReg(DestTmp);
324 MachineInstr *ADDu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
325 .addDef(Dest)
326 .addUse(DestTmp)
327 .addUse(MF.getInfo<MipsFunctionInfo>()
328 ->getGlobalBaseRegForGlobalISel());
329 if (!constrainSelectedInstRegOperands(*ADDu, TII, TRI, RBI))
330 return false;
331 }
332
333 MachineInstr *Branch =
334 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoIndirectBranch))
335 .addUse(Dest);
336 if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI))
337 return false;
338
339 I.eraseFromParent();
340 return true;
341 }
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000342 case G_PHI: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000343 const Register DestReg = I.getOperand(0).getReg();
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000344 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
345
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000346 const TargetRegisterClass *DefRC = nullptr;
Daniel Sanders2bea69b2019-08-01 23:27:28 +0000347 if (Register::isPhysicalRegister(DestReg))
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000348 DefRC = TRI.getRegClass(DestReg);
349 else
350 DefRC = getRegClassForTypeOnBank(OpSize,
351 *RBI.getRegBank(DestReg, MRI, TRI), RBI);
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000352
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000353 I.setDesc(TII.get(TargetOpcode::PHI));
354 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
355 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000356 case G_STORE:
Petar Avramovic79df8592019-01-24 10:27:21 +0000357 case G_LOAD:
358 case G_ZEXTLOAD:
359 case G_SEXTLOAD: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000360 const Register DestReg = I.getOperand(0).getReg();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000361 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
362 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
Petar Avramovic79df8592019-01-24 10:27:21 +0000363 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000364
Petar Avramovic7b314912019-07-10 12:55:21 +0000365 if (DestRegBank == Mips::GPRBRegBankID && OpSize != 32)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000366 return false;
367
Petar Avramovic7b314912019-07-10 12:55:21 +0000368 if (DestRegBank == Mips::FPRBRegBankID && OpSize != 32 && OpSize != 64)
369 return false;
370
371 const unsigned NewOpc = selectLoadStoreOpCode(
372 I.getOpcode(), OpMemSizeInBytes, DestRegBank, STI.isFP64bit());
Petar Avramovic79df8592019-01-24 10:27:21 +0000373 if (NewOpc == I.getOpcode())
374 return false;
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000375
Petar Avramovic8a40ced2019-08-01 09:40:13 +0000376 MachineOperand BaseAddr = I.getOperand(1);
377 int64_t SignedOffset = 0;
378 // Try to fold load/store + G_GEP + G_CONSTANT
379 // %SignedOffset:(s32) = G_CONSTANT i32 16_bit_signed_immediate
380 // %Addr:(p0) = G_GEP %BaseAddr, %SignedOffset
381 // %LoadResult/%StoreSrc = load/store %Addr(p0)
382 // into:
383 // %LoadResult/%StoreSrc = NewOpc %BaseAddr(p0), 16_bit_signed_immediate
384
385 MachineInstr *Addr = MRI.getVRegDef(I.getOperand(1).getReg());
386 if (Addr->getOpcode() == G_GEP) {
387 MachineInstr *Offset = MRI.getVRegDef(Addr->getOperand(2).getReg());
388 if (Offset->getOpcode() == G_CONSTANT) {
389 APInt OffsetValue = Offset->getOperand(1).getCImm()->getValue();
390 if (OffsetValue.isSignedIntN(16)) {
391 BaseAddr = Addr->getOperand(1);
392 SignedOffset = OffsetValue.getSExtValue();
393 }
394 }
395 }
396
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000397 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
398 .add(I.getOperand(0))
Petar Avramovic8a40ced2019-08-01 09:40:13 +0000399 .add(BaseAddr)
400 .addImm(SignedOffset)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000401 .addMemOperand(*I.memoperands_begin());
402 break;
403 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000404 case G_UDIV:
405 case G_UREM:
406 case G_SDIV:
407 case G_SREM: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000408 Register HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000409 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
410 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
411
412 MachineInstr *PseudoDIV, *PseudoMove;
413 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
414 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
415 .addDef(HILOReg)
416 .add(I.getOperand(1))
417 .add(I.getOperand(2));
418 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
419 return false;
420
421 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
422 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
423 .addDef(I.getOperand(0).getReg())
424 .addUse(HILOReg);
425 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
426 return false;
427
428 I.eraseFromParent();
429 return true;
430 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000431 case G_SELECT: {
432 // Handle operands with pointer type.
433 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
434 .add(I.getOperand(0))
435 .add(I.getOperand(2))
436 .add(I.getOperand(1))
437 .add(I.getOperand(3));
438 break;
439 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000440 case G_CONSTANT: {
Petar Avramovic3e0da142019-03-15 07:07:50 +0000441 MachineIRBuilder B(I);
442 if (!materialize32BitImm(I.getOperand(0).getReg(),
443 I.getOperand(1).getCImm()->getValue(), B))
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000444 return false;
445
446 I.eraseFromParent();
447 return true;
448 }
Petar Avramovic1af05df2019-03-28 16:58:12 +0000449 case G_FCONSTANT: {
450 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
451 APInt APImm = FPimm.bitcastToAPInt();
452 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
453
454 if (Size == 32) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000455 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000456 MachineIRBuilder B(I);
457 if (!materialize32BitImm(GPRReg, APImm, B))
458 return false;
459
460 MachineInstrBuilder MTC1 =
461 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
462 if (!MTC1.constrainAllUses(TII, TRI, RBI))
463 return false;
464 }
465 if (Size == 64) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000466 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
467 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000468 MachineIRBuilder B(I);
469 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
470 return false;
471 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
472 return false;
473
474 MachineInstrBuilder PairF64 = B.buildInstr(
475 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
476 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
477 if (!PairF64.constrainAllUses(TII, TRI, RBI))
478 return false;
479 }
480
481 I.eraseFromParent();
482 return true;
483 }
Petar Avramovic0a1fd352019-06-06 09:22:37 +0000484 case G_FABS: {
485 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
486 unsigned FABSOpcode =
487 Size == 32 ? Mips::FABS_S
488 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
489 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode))
490 .add(I.getOperand(0))
491 .add(I.getOperand(1));
492 break;
493 }
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000494 case G_FPTOSI: {
495 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits();
496 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
Fangrui Songddd056c2019-06-21 01:51:50 +0000497 (void)ToSize;
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000498 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
499 assert((FromSize == 32 || FromSize == 64) &&
500 "Unsupported floating point size for G_FPTOSI");
501
502 unsigned Opcode;
503 if (FromSize == 32)
504 Opcode = Mips::TRUNC_W_S;
505 else
506 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
507 unsigned ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass);
508 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
509 .addDef(ResultInFPR)
510 .addUse(I.getOperand(1).getReg());
511 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI))
512 return false;
513
514 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1))
515 .addDef(I.getOperand(0).getReg())
516 .addUse(ResultInFPR);
517 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
518 return false;
519
520 I.eraseFromParent();
521 return true;
522 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000523 case G_GLOBAL_VALUE: {
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000524 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000525 if (MF.getTarget().isPositionIndependent()) {
526 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
527 .addDef(I.getOperand(0).getReg())
528 .addReg(MF.getInfo<MipsFunctionInfo>()
529 ->getGlobalBaseRegForGlobalISel())
530 .addGlobalAddress(GVal);
531 // Global Values that don't have local linkage are handled differently
532 // when they are part of call sequence. MipsCallLowering::lowerCall
533 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
534 // MO_GOT_CALL flag when Callee doesn't have local linkage.
535 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL)
536 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL);
537 else
538 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT);
539 LWGOT->addMemOperand(
540 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
541 MachineMemOperand::MOLoad, 4, 4));
542 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI))
543 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000544
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000545 if (GVal->hasLocalLinkage()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000546 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000547 LWGOT->getOperand(0).setReg(LWGOTDef);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000548
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000549 MachineInstr *ADDiu =
550 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000551 .addDef(I.getOperand(0).getReg())
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000552 .addReg(LWGOTDef)
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000553 .addGlobalAddress(GVal);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000554 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
555 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
556 return false;
557 }
558 } else {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000559 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000560
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000561 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
562 .addDef(LUiReg)
563 .addGlobalAddress(GVal);
564 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
565 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
566 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000567
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000568 MachineInstr *ADDiu =
569 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
570 .addDef(I.getOperand(0).getReg())
571 .addUse(LUiReg)
572 .addGlobalAddress(GVal);
573 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
574 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
575 return false;
576 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000577 I.eraseFromParent();
578 return true;
579 }
Petar Avramoviccaef9302019-08-08 10:21:12 +0000580 case G_JUMP_TABLE: {
581 if (MF.getTarget().isPositionIndependent()) {
582 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
583 .addDef(I.getOperand(0).getReg())
584 .addReg(MF.getInfo<MipsFunctionInfo>()
585 ->getGlobalBaseRegForGlobalISel())
586 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_GOT)
587 .addMemOperand(
588 MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
589 MachineMemOperand::MOLoad, 4, 4));
590 } else {
591 MI =
592 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
593 .addDef(I.getOperand(0).getReg())
594 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_ABS_HI);
595 }
596 break;
597 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000598 case G_ICMP: {
599 struct Instr {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000600 unsigned Opcode;
601 Register Def, LHS, RHS;
602 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000603 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000604
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000605 bool hasImm() const {
606 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
607 return true;
608 return false;
609 }
610 };
611
612 SmallVector<struct Instr, 2> Instructions;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000613 Register ICMPReg = I.getOperand(0).getReg();
614 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
615 Register LHS = I.getOperand(2).getReg();
616 Register RHS = I.getOperand(3).getReg();
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000617 CmpInst::Predicate Cond =
618 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
619
620 switch (Cond) {
621 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
622 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
623 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
624 break;
625 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
626 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
627 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
628 break;
629 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
630 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
631 break;
632 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
633 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
634 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
635 break;
636 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
637 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
638 break;
639 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
640 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
641 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
642 break;
643 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
644 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
645 break;
646 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
647 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
648 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
649 break;
650 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
651 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
652 break;
653 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
654 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
655 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
656 break;
657 default:
658 return false;
659 }
660
661 MachineIRBuilder B(I);
662 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000663 MachineInstrBuilder MIB = B.buildInstr(
664 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000665
666 if (Instruction.hasImm())
667 MIB.addImm(Instruction.RHS);
668 else
669 MIB.addUse(Instruction.RHS);
670
671 if (!MIB.constrainAllUses(TII, TRI, RBI))
672 return false;
673 }
674
675 I.eraseFromParent();
676 return true;
677 }
Petar Avramovic22e99c42019-06-05 14:03:13 +0000678 case G_FCMP: {
679 unsigned MipsFCMPCondCode;
680 bool isLogicallyNegated;
681 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
682 I.getOperand(1).getPredicate())) {
683 case CmpInst::FCMP_UNO: // Unordered
684 case CmpInst::FCMP_ORD: // Ordered (OR)
685 MipsFCMPCondCode = Mips::FCOND_UN;
686 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
687 break;
688 case CmpInst::FCMP_OEQ: // Equal
689 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
690 MipsFCMPCondCode = Mips::FCOND_OEQ;
691 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
692 break;
693 case CmpInst::FCMP_UEQ: // Unordered or Equal
694 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
695 MipsFCMPCondCode = Mips::FCOND_UEQ;
696 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
697 break;
698 case CmpInst::FCMP_OLT: // Ordered or Less Than
699 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
700 MipsFCMPCondCode = Mips::FCOND_OLT;
701 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
702 break;
703 case CmpInst::FCMP_ULT: // Unordered or Less Than
704 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
705 MipsFCMPCondCode = Mips::FCOND_ULT;
706 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
707 break;
708 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
709 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
710 MipsFCMPCondCode = Mips::FCOND_OLE;
711 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
712 break;
713 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
714 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
715 MipsFCMPCondCode = Mips::FCOND_ULE;
716 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
717 break;
718 default:
719 return false;
720 }
721
722 // Default compare result in gpr register will be `true`.
723 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
724 // using MOVF_I. When orignal predicate (Cond) is logically negated
725 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
726 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
727
728 unsigned TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
729 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
730 .addDef(TrueInReg)
731 .addUse(Mips::ZERO)
732 .addImm(1);
733
734 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
735 unsigned FCMPOpcode =
736 Size == 32 ? Mips::FCMP_S32
737 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
738 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode))
739 .addUse(I.getOperand(2).getReg())
740 .addUse(I.getOperand(3).getReg())
741 .addImm(MipsFCMPCondCode);
742 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI))
743 return false;
744
745 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode))
746 .addDef(I.getOperand(0).getReg())
747 .addUse(Mips::ZERO)
748 .addUse(Mips::FCC0)
749 .addUse(TrueInReg);
750 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
751 return false;
752
753 I.eraseFromParent();
754 return true;
755 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000756 default:
757 return false;
758 }
759
760 I.eraseFromParent();
761 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000762}
763
764namespace llvm {
765InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
766 MipsSubtarget &Subtarget,
767 MipsRegisterBankInfo &RBI) {
768 return new MipsInstructionSelector(TM, Subtarget, RBI);
769}
770} // end namespace llvm