blob: 8426579720c360b48685c252cb3efce66e3ed175 [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 Jovanovic021e4c82018-07-16 13:29:32 +0000439 case G_CONSTANT: {
Petar Avramovic3e0da142019-03-15 07:07:50 +0000440 MachineIRBuilder B(I);
441 if (!materialize32BitImm(I.getOperand(0).getReg(),
442 I.getOperand(1).getCImm()->getValue(), B))
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000443 return false;
444
445 I.eraseFromParent();
446 return true;
447 }
Petar Avramovic1af05df2019-03-28 16:58:12 +0000448 case G_FCONSTANT: {
449 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
450 APInt APImm = FPimm.bitcastToAPInt();
451 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
452
453 if (Size == 32) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000454 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000455 MachineIRBuilder B(I);
456 if (!materialize32BitImm(GPRReg, APImm, B))
457 return false;
458
459 MachineInstrBuilder MTC1 =
460 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
461 if (!MTC1.constrainAllUses(TII, TRI, RBI))
462 return false;
463 }
464 if (Size == 64) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000465 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
466 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000467 MachineIRBuilder B(I);
468 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
469 return false;
470 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
471 return false;
472
473 MachineInstrBuilder PairF64 = B.buildInstr(
474 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
475 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
476 if (!PairF64.constrainAllUses(TII, TRI, RBI))
477 return false;
478 }
479
480 I.eraseFromParent();
481 return true;
482 }
Petar Avramovic0a1fd352019-06-06 09:22:37 +0000483 case G_FABS: {
484 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
485 unsigned FABSOpcode =
486 Size == 32 ? Mips::FABS_S
487 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
488 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode))
489 .add(I.getOperand(0))
490 .add(I.getOperand(1));
491 break;
492 }
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000493 case G_FPTOSI: {
494 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits();
495 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
Fangrui Songddd056c2019-06-21 01:51:50 +0000496 (void)ToSize;
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000497 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
498 assert((FromSize == 32 || FromSize == 64) &&
499 "Unsupported floating point size for G_FPTOSI");
500
501 unsigned Opcode;
502 if (FromSize == 32)
503 Opcode = Mips::TRUNC_W_S;
504 else
505 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
506 unsigned ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass);
507 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
508 .addDef(ResultInFPR)
509 .addUse(I.getOperand(1).getReg());
510 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI))
511 return false;
512
513 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1))
514 .addDef(I.getOperand(0).getReg())
515 .addUse(ResultInFPR);
516 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
517 return false;
518
519 I.eraseFromParent();
520 return true;
521 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000522 case G_GLOBAL_VALUE: {
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000523 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000524 if (MF.getTarget().isPositionIndependent()) {
525 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
526 .addDef(I.getOperand(0).getReg())
527 .addReg(MF.getInfo<MipsFunctionInfo>()
528 ->getGlobalBaseRegForGlobalISel())
529 .addGlobalAddress(GVal);
530 // Global Values that don't have local linkage are handled differently
531 // when they are part of call sequence. MipsCallLowering::lowerCall
532 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
533 // MO_GOT_CALL flag when Callee doesn't have local linkage.
534 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL)
535 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL);
536 else
537 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT);
538 LWGOT->addMemOperand(
539 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
540 MachineMemOperand::MOLoad, 4, 4));
541 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI))
542 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000543
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000544 if (GVal->hasLocalLinkage()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000545 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000546 LWGOT->getOperand(0).setReg(LWGOTDef);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000547
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000548 MachineInstr *ADDiu =
549 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000550 .addDef(I.getOperand(0).getReg())
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000551 .addReg(LWGOTDef)
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000552 .addGlobalAddress(GVal);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000553 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
554 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
555 return false;
556 }
557 } else {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000558 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000559
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000560 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
561 .addDef(LUiReg)
562 .addGlobalAddress(GVal);
563 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
564 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
565 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000566
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000567 MachineInstr *ADDiu =
568 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
569 .addDef(I.getOperand(0).getReg())
570 .addUse(LUiReg)
571 .addGlobalAddress(GVal);
572 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
573 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
574 return false;
575 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000576 I.eraseFromParent();
577 return true;
578 }
Petar Avramoviccaef9302019-08-08 10:21:12 +0000579 case G_JUMP_TABLE: {
580 if (MF.getTarget().isPositionIndependent()) {
581 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
582 .addDef(I.getOperand(0).getReg())
583 .addReg(MF.getInfo<MipsFunctionInfo>()
584 ->getGlobalBaseRegForGlobalISel())
585 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_GOT)
586 .addMemOperand(
587 MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
588 MachineMemOperand::MOLoad, 4, 4));
589 } else {
590 MI =
591 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
592 .addDef(I.getOperand(0).getReg())
593 .addJumpTableIndex(I.getOperand(1).getIndex(), MipsII::MO_ABS_HI);
594 }
595 break;
596 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000597 case G_ICMP: {
598 struct Instr {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000599 unsigned Opcode;
600 Register Def, LHS, RHS;
601 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000602 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000603
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000604 bool hasImm() const {
605 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
606 return true;
607 return false;
608 }
609 };
610
611 SmallVector<struct Instr, 2> Instructions;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000612 Register ICMPReg = I.getOperand(0).getReg();
613 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
614 Register LHS = I.getOperand(2).getReg();
615 Register RHS = I.getOperand(3).getReg();
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000616 CmpInst::Predicate Cond =
617 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
618
619 switch (Cond) {
620 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
621 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
622 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
623 break;
624 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
625 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
626 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
627 break;
628 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
629 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
630 break;
631 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
632 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
633 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
634 break;
635 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
636 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
637 break;
638 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
639 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
640 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
641 break;
642 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
643 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
644 break;
645 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
646 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
647 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
648 break;
649 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
650 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
651 break;
652 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
653 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
654 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
655 break;
656 default:
657 return false;
658 }
659
660 MachineIRBuilder B(I);
661 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000662 MachineInstrBuilder MIB = B.buildInstr(
663 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000664
665 if (Instruction.hasImm())
666 MIB.addImm(Instruction.RHS);
667 else
668 MIB.addUse(Instruction.RHS);
669
670 if (!MIB.constrainAllUses(TII, TRI, RBI))
671 return false;
672 }
673
674 I.eraseFromParent();
675 return true;
676 }
Petar Avramovic22e99c42019-06-05 14:03:13 +0000677 case G_FCMP: {
678 unsigned MipsFCMPCondCode;
679 bool isLogicallyNegated;
680 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
681 I.getOperand(1).getPredicate())) {
682 case CmpInst::FCMP_UNO: // Unordered
683 case CmpInst::FCMP_ORD: // Ordered (OR)
684 MipsFCMPCondCode = Mips::FCOND_UN;
685 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
686 break;
687 case CmpInst::FCMP_OEQ: // Equal
688 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
689 MipsFCMPCondCode = Mips::FCOND_OEQ;
690 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
691 break;
692 case CmpInst::FCMP_UEQ: // Unordered or Equal
693 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
694 MipsFCMPCondCode = Mips::FCOND_UEQ;
695 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
696 break;
697 case CmpInst::FCMP_OLT: // Ordered or Less Than
698 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
699 MipsFCMPCondCode = Mips::FCOND_OLT;
700 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
701 break;
702 case CmpInst::FCMP_ULT: // Unordered or Less Than
703 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
704 MipsFCMPCondCode = Mips::FCOND_ULT;
705 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
706 break;
707 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
708 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
709 MipsFCMPCondCode = Mips::FCOND_OLE;
710 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
711 break;
712 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
713 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
714 MipsFCMPCondCode = Mips::FCOND_ULE;
715 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
716 break;
717 default:
718 return false;
719 }
720
721 // Default compare result in gpr register will be `true`.
722 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
723 // using MOVF_I. When orignal predicate (Cond) is logically negated
724 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
725 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
726
727 unsigned TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
728 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
729 .addDef(TrueInReg)
730 .addUse(Mips::ZERO)
731 .addImm(1);
732
733 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
734 unsigned FCMPOpcode =
735 Size == 32 ? Mips::FCMP_S32
736 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
737 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode))
738 .addUse(I.getOperand(2).getReg())
739 .addUse(I.getOperand(3).getReg())
740 .addImm(MipsFCMPCondCode);
741 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI))
742 return false;
743
744 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode))
745 .addDef(I.getOperand(0).getReg())
746 .addUse(Mips::ZERO)
747 .addUse(Mips::FCC0)
748 .addUse(TrueInReg);
749 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
750 return false;
751
752 I.eraseFromParent();
753 return true;
754 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000755 default:
756 return false;
757 }
758
759 I.eraseFromParent();
760 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000761}
762
763namespace llvm {
764InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
765 MipsSubtarget &Subtarget,
766 MipsRegisterBankInfo &RBI) {
767 return new MipsInstructionSelector(TM, Subtarget, RBI);
768}
769} // end namespace llvm