1//===- MipsInstructionSelector.cpp ------------------------------*- C++ -*-===//
2//
3// 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
6//
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
14#include "MCTargetDesc/MipsInstPrinter.h"
15#include "MipsMachineFunction.h"
16#include "MipsRegisterBankInfo.h"
17#include "MipsTargetMachine.h"
18#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
19#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
20#include "llvm/CodeGen/MachineJumpTableInfo.h"
21#include "llvm/IR/IntrinsicsMips.h"
22
23#define DEBUG_TYPE "mips-isel"
24
25using namespace llvm;
26
27namespace {
28
29#define GET_GLOBALISEL_PREDICATE_BITSET
30#include "MipsGenGlobalISel.inc"
31#undef GET_GLOBALISEL_PREDICATE_BITSET
32
33class MipsInstructionSelector : public InstructionSelector {
34public:
35 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
36 const MipsRegisterBankInfo &RBI);
37
38 bool select(MachineInstr &I) override;
39 static const char *getName() { return DEBUG_TYPE; }
40
41private:
42 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
43 bool isRegInGprb(Register Reg, MachineRegisterInfo &MRI) const;
44 bool isRegInFprb(Register Reg, MachineRegisterInfo &MRI) const;
45 bool materialize32BitImm(Register DestReg, APInt Imm,
46 MachineIRBuilder &B) const;
47 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
48 const TargetRegisterClass *
49 getRegClassForTypeOnBank(Register Reg, MachineRegisterInfo &MRI) const;
50 unsigned selectLoadStoreOpCode(MachineInstr &I,
51 MachineRegisterInfo &MRI) const;
52 bool buildUnalignedStore(MachineInstr &I, unsigned Opc,
53 MachineOperand &BaseAddr, unsigned Offset,
54 MachineMemOperand *MMO) const;
55 bool buildUnalignedLoad(MachineInstr &I, unsigned Opc, Register Dest,
56 MachineOperand &BaseAddr, unsigned Offset,
57 Register TiedDest, MachineMemOperand *MMO) const;
58
59 const MipsTargetMachine &TM;
60 const MipsSubtarget &STI;
61 const MipsInstrInfo &TII;
62 const MipsRegisterInfo &TRI;
63 const MipsRegisterBankInfo &RBI;
64
65#define GET_GLOBALISEL_PREDICATES_DECL
66#include "MipsGenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATES_DECL
68
69#define GET_GLOBALISEL_TEMPORARIES_DECL
70#include "MipsGenGlobalISel.inc"
71#undef GET_GLOBALISEL_TEMPORARIES_DECL
72};
73
74} // end anonymous namespace
75
76#define GET_GLOBALISEL_IMPL
77#include "MipsGenGlobalISel.inc"
78#undef GET_GLOBALISEL_IMPL
79
80MipsInstructionSelector::MipsInstructionSelector(
81 const MipsTargetMachine &TM, const MipsSubtarget &STI,
82 const MipsRegisterBankInfo &RBI)
83 : TM(TM), STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()),
84 RBI(RBI),
85
86#define GET_GLOBALISEL_PREDICATES_INIT
87#include "MipsGenGlobalISel.inc"
88#undef GET_GLOBALISEL_PREDICATES_INIT
89#define GET_GLOBALISEL_TEMPORARIES_INIT
90#include "MipsGenGlobalISel.inc"
91#undef GET_GLOBALISEL_TEMPORARIES_INIT
92{
93}
94
95bool MipsInstructionSelector::isRegInGprb(Register Reg,
96 MachineRegisterInfo &MRI) const {
97 return RBI.getRegBank(Reg, MRI, TRI)->getID() == Mips::GPRBRegBankID;
98}
99
100bool MipsInstructionSelector::isRegInFprb(Register Reg,
101 MachineRegisterInfo &MRI) const {
102 return RBI.getRegBank(Reg, MRI, TRI)->getID() == Mips::FPRBRegBankID;
103}
104
105bool MipsInstructionSelector::selectCopy(MachineInstr &I,
106 MachineRegisterInfo &MRI) const {
107 Register DstReg = I.getOperand(i: 0).getReg();
108 if (DstReg.isPhysical())
109 return true;
110
111 const TargetRegisterClass *RC = getRegClassForTypeOnBank(Reg: DstReg, MRI);
112 if (!RBI.constrainGenericRegister(Reg: DstReg, RC: *RC, MRI)) {
113 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
114 << " operand\n");
115 return false;
116 }
117 return true;
118}
119
120const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank(
121 Register Reg, MachineRegisterInfo &MRI) const {
122 const LLT Ty = MRI.getType(Reg);
123 const unsigned TySize = Ty.getSizeInBits();
124
125 if (isRegInGprb(Reg, MRI)) {
126 assert((Ty.isScalar() || Ty.isPointer()) &&
127 (TySize == 32 || TySize == 64) &&
128 "Register class not available for LLT, register bank combination");
129 if (TySize == 32)
130 return &Mips::GPR32RegClass;
131 if (TySize == 64)
132 return &Mips::GPR64RegClass;
133 }
134
135 if (isRegInFprb(Reg, MRI)) {
136 if (Ty.isScalar()) {
137 assert((TySize == 32 || TySize == 64) &&
138 "Register class not available for LLT, register bank combination");
139 if (TySize == 32)
140 return &Mips::FGR32RegClass;
141 return STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass;
142 }
143 }
144
145 llvm_unreachable("Unsupported register bank.");
146}
147
148bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm,
149 MachineIRBuilder &B) const {
150 assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
151 // Ori zero extends immediate. Used for values with zeros in high 16 bits.
152 if (Imm.getHiBits(numBits: 16).isZero()) {
153 MachineInstr *Inst =
154 B.buildInstr(Opc: Mips::ORi, DstOps: {DestReg}, SrcOps: {Register(Mips::ZERO)})
155 .addImm(Val: Imm.getLoBits(numBits: 16).getLimitedValue());
156 constrainSelectedInstRegOperands(I&: *Inst, TII, TRI, RBI);
157 return true;
158 }
159 // Lui places immediate in high 16 bits and sets low 16 bits to zero.
160 if (Imm.getLoBits(numBits: 16).isZero()) {
161 MachineInstr *Inst = B.buildInstr(Opc: Mips::LUi, DstOps: {DestReg}, SrcOps: {})
162 .addImm(Val: Imm.getHiBits(numBits: 16).getLimitedValue());
163 constrainSelectedInstRegOperands(I&: *Inst, TII, TRI, RBI);
164 return true;
165 }
166 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits.
167 if (Imm.isSignedIntN(N: 16)) {
168 MachineInstr *Inst =
169 B.buildInstr(Opc: Mips::ADDiu, DstOps: {DestReg}, SrcOps: {Register(Mips::ZERO)})
170 .addImm(Val: Imm.getLoBits(numBits: 16).getLimitedValue());
171 constrainSelectedInstRegOperands(I&: *Inst, TII, TRI, RBI);
172 return true;
173 }
174 // Values that cannot be materialized with single immediate instruction.
175 Register LUiReg = B.getMRI()->createVirtualRegister(RegClass: &Mips::GPR32RegClass);
176 MachineInstr *LUi = B.buildInstr(Opc: Mips::LUi, DstOps: {LUiReg}, SrcOps: {})
177 .addImm(Val: Imm.getHiBits(numBits: 16).getLimitedValue());
178 MachineInstr *ORi = B.buildInstr(Opc: Mips::ORi, DstOps: {DestReg}, SrcOps: {LUiReg})
179 .addImm(Val: Imm.getLoBits(numBits: 16).getLimitedValue());
180 constrainSelectedInstRegOperands(I&: *LUi, TII, TRI, RBI);
181 constrainSelectedInstRegOperands(I&: *ORi, TII, TRI, RBI);
182 return true;
183}
184
185/// When I.getOpcode() is returned, we failed to select MIPS instruction opcode.
186unsigned
187MipsInstructionSelector::selectLoadStoreOpCode(MachineInstr &I,
188 MachineRegisterInfo &MRI) const {
189 const Register ValueReg = I.getOperand(i: 0).getReg();
190 const LLT Ty = MRI.getType(Reg: ValueReg);
191 const unsigned TySize = Ty.getSizeInBits();
192 const unsigned MemSizeInBytes =
193 (*I.memoperands_begin())->getSize().getValue();
194 unsigned Opc = I.getOpcode();
195 const bool isStore = Opc == TargetOpcode::G_STORE;
196
197 if (isRegInGprb(Reg: ValueReg, MRI)) {
198 assert(((Ty.isScalar() && TySize == 32) ||
199 (Ty.isPointer() && TySize == 32 && MemSizeInBytes == 4)) &&
200 "Unsupported register bank, LLT, MemSizeInBytes combination");
201 (void)TySize;
202 if (isStore)
203 switch (MemSizeInBytes) {
204 case 4:
205 return Mips::SW;
206 case 2:
207 return Mips::SH;
208 case 1:
209 return Mips::SB;
210 default:
211 return Opc;
212 }
213 else
214 // Unspecified extending load is selected into zeroExtending load.
215 switch (MemSizeInBytes) {
216 case 4:
217 return Mips::LW;
218 case 2:
219 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
220 case 1:
221 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
222 default:
223 return Opc;
224 }
225 }
226
227 if (isRegInFprb(Reg: ValueReg, MRI)) {
228 if (Ty.isScalar()) {
229 assert(((TySize == 32 && MemSizeInBytes == 4) ||
230 (TySize == 64 && MemSizeInBytes == 8)) &&
231 "Unsupported register bank, LLT, MemSizeInBytes combination");
232
233 if (MemSizeInBytes == 4)
234 return isStore ? Mips::SWC1 : Mips::LWC1;
235
236 if (STI.isFP64bit())
237 return isStore ? Mips::SDC164 : Mips::LDC164;
238 return isStore ? Mips::SDC1 : Mips::LDC1;
239 }
240
241 if (Ty.isVector()) {
242 assert(STI.hasMSA() && "Vector instructions require target with MSA.");
243 assert((TySize == 128 && MemSizeInBytes == 16) &&
244 "Unsupported register bank, LLT, MemSizeInBytes combination");
245 switch (Ty.getElementType().getSizeInBits()) {
246 case 8:
247 return isStore ? Mips::ST_B : Mips::LD_B;
248 case 16:
249 return isStore ? Mips::ST_H : Mips::LD_H;
250 case 32:
251 return isStore ? Mips::ST_W : Mips::LD_W;
252 case 64:
253 return isStore ? Mips::ST_D : Mips::LD_D;
254 default:
255 return Opc;
256 }
257 }
258 }
259
260 return Opc;
261}
262
263bool MipsInstructionSelector::buildUnalignedStore(
264 MachineInstr &I, unsigned Opc, MachineOperand &BaseAddr, unsigned Offset,
265 MachineMemOperand *MMO) const {
266 MachineInstr *NewInst =
267 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Opc))
268 .add(MO: I.getOperand(i: 0))
269 .add(MO: BaseAddr)
270 .addImm(Val: Offset)
271 .addMemOperand(MMO);
272 constrainSelectedInstRegOperands(I&: *NewInst, TII, TRI, RBI);
273 return true;
274}
275
276bool MipsInstructionSelector::buildUnalignedLoad(
277 MachineInstr &I, unsigned Opc, Register Dest, MachineOperand &BaseAddr,
278 unsigned Offset, Register TiedDest, MachineMemOperand *MMO) const {
279 MachineInstr *NewInst =
280 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Opc))
281 .addDef(RegNo: Dest)
282 .add(MO: BaseAddr)
283 .addImm(Val: Offset)
284 .addUse(RegNo: TiedDest)
285 .addMemOperand(MMO: *I.memoperands_begin());
286 constrainSelectedInstRegOperands(I&: *NewInst, TII, TRI, RBI);
287 return true;
288}
289
290bool MipsInstructionSelector::select(MachineInstr &I) {
291
292 MachineBasicBlock &MBB = *I.getParent();
293 MachineFunction &MF = *MBB.getParent();
294 MachineRegisterInfo &MRI = MF.getRegInfo();
295
296 if (!isPreISelGenericOpcode(Opcode: I.getOpcode())) {
297 if (I.isCopy())
298 return selectCopy(I, MRI);
299
300 return true;
301 }
302
303 if (I.getOpcode() == Mips::G_MUL &&
304 isRegInGprb(Reg: I.getOperand(i: 0).getReg(), MRI)) {
305 MachineInstr *Mul = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::MUL))
306 .add(MO: I.getOperand(i: 0))
307 .add(MO: I.getOperand(i: 1))
308 .add(MO: I.getOperand(i: 2));
309 constrainSelectedInstRegOperands(I&: *Mul, TII, TRI, RBI);
310 Mul->getOperand(i: 3).setIsDead(true);
311 Mul->getOperand(i: 4).setIsDead(true);
312
313 I.eraseFromParent();
314 return true;
315 }
316
317 if (selectImpl(I, CoverageInfo&: *CoverageInfo))
318 return true;
319
320 MachineInstr *MI = nullptr;
321 using namespace TargetOpcode;
322
323 switch (I.getOpcode()) {
324 case G_UMULH: {
325 Register PseudoMULTuReg = MRI.createVirtualRegister(RegClass: &Mips::ACC64RegClass);
326 MachineInstr *PseudoMULTu, *PseudoMove;
327
328 PseudoMULTu = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::PseudoMULTu))
329 .addDef(RegNo: PseudoMULTuReg)
330 .add(MO: I.getOperand(i: 1))
331 .add(MO: I.getOperand(i: 2));
332 constrainSelectedInstRegOperands(I&: *PseudoMULTu, TII, TRI, RBI);
333
334 PseudoMove = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::PseudoMFHI))
335 .addDef(RegNo: I.getOperand(i: 0).getReg())
336 .addUse(RegNo: PseudoMULTuReg);
337 constrainSelectedInstRegOperands(I&: *PseudoMove, TII, TRI, RBI);
338
339 I.eraseFromParent();
340 return true;
341 }
342 case G_PTR_ADD: {
343 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDu))
344 .add(MO: I.getOperand(i: 0))
345 .add(MO: I.getOperand(i: 1))
346 .add(MO: I.getOperand(i: 2));
347 break;
348 }
349 case G_INTTOPTR:
350 case G_PTRTOINT: {
351 I.setDesc(TII.get(Opcode: COPY));
352 return selectCopy(I, MRI);
353 }
354 case G_FRAME_INDEX: {
355 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
356 .add(MO: I.getOperand(i: 0))
357 .add(MO: I.getOperand(i: 1))
358 .addImm(Val: 0);
359 break;
360 }
361 case G_BRJT: {
362 unsigned EntrySize =
363 MF.getJumpTableInfo()->getEntrySize(TD: MF.getDataLayout());
364 assert(isPowerOf2_32(EntrySize) &&
365 "Non-power-of-two jump-table entry size not supported.");
366
367 Register JTIndex = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
368 MachineInstr *SLL = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::SLL))
369 .addDef(RegNo: JTIndex)
370 .addUse(RegNo: I.getOperand(i: 2).getReg())
371 .addImm(Val: Log2_32(Value: EntrySize));
372 constrainSelectedInstRegOperands(I&: *SLL, TII, TRI, RBI);
373
374 Register DestAddress = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
375 MachineInstr *ADDu = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDu))
376 .addDef(RegNo: DestAddress)
377 .addUse(RegNo: I.getOperand(i: 0).getReg())
378 .addUse(RegNo: JTIndex);
379 constrainSelectedInstRegOperands(I&: *ADDu, TII, TRI, RBI);
380
381 Register Dest = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
382 MachineInstr *LW =
383 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LW))
384 .addDef(RegNo: Dest)
385 .addUse(RegNo: DestAddress)
386 .addJumpTableIndex(Idx: I.getOperand(i: 1).getIndex(), TargetFlags: MipsII::MO_ABS_LO)
387 .addMemOperand(MMO: MF.getMachineMemOperand(
388 PtrInfo: MachinePointerInfo(), F: MachineMemOperand::MOLoad, Size: 4, BaseAlignment: Align(4)));
389 constrainSelectedInstRegOperands(I&: *LW, TII, TRI, RBI);
390
391 if (MF.getTarget().isPositionIndependent()) {
392 Register DestTmp = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
393 LW->getOperand(i: 0).setReg(DestTmp);
394 MachineInstr *ADDu = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDu))
395 .addDef(RegNo: Dest)
396 .addUse(RegNo: DestTmp)
397 .addUse(RegNo: MF.getInfo<MipsFunctionInfo>()
398 ->getGlobalBaseRegForGlobalISel(MF));
399 constrainSelectedInstRegOperands(I&: *ADDu, TII, TRI, RBI);
400 }
401
402 MachineInstr *Branch =
403 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::PseudoIndirectBranch))
404 .addUse(RegNo: Dest);
405 constrainSelectedInstRegOperands(I&: *Branch, TII, TRI, RBI);
406
407 I.eraseFromParent();
408 return true;
409 }
410 case G_PHI: {
411 const Register DestReg = I.getOperand(i: 0).getReg();
412
413 const TargetRegisterClass *DefRC = nullptr;
414 if (DestReg.isPhysical())
415 DefRC = TRI.getRegClass(i: DestReg);
416 else
417 DefRC = getRegClassForTypeOnBank(Reg: DestReg, MRI);
418
419 I.setDesc(TII.get(Opcode: TargetOpcode::PHI));
420 return RBI.constrainGenericRegister(Reg: DestReg, RC: *DefRC, MRI);
421 }
422 case G_STORE:
423 case G_LOAD:
424 case G_ZEXTLOAD:
425 case G_SEXTLOAD: {
426 auto MMO = *I.memoperands_begin();
427 MachineOperand BaseAddr = I.getOperand(i: 1);
428 int64_t SignedOffset = 0;
429 // Try to fold load/store + G_PTR_ADD + G_CONSTANT
430 // %SignedOffset:(s32) = G_CONSTANT i32 16_bit_signed_immediate
431 // %Addr:(p0) = G_PTR_ADD %BaseAddr, %SignedOffset
432 // %LoadResult/%StoreSrc = load/store %Addr(p0)
433 // into:
434 // %LoadResult/%StoreSrc = NewOpc %BaseAddr(p0), 16_bit_signed_immediate
435
436 MachineInstr *Addr = MRI.getVRegDef(Reg: I.getOperand(i: 1).getReg());
437 if (Addr->getOpcode() == G_PTR_ADD) {
438 MachineInstr *Offset = MRI.getVRegDef(Reg: Addr->getOperand(i: 2).getReg());
439 if (Offset->getOpcode() == G_CONSTANT) {
440 APInt OffsetValue = Offset->getOperand(i: 1).getCImm()->getValue();
441 if (OffsetValue.isSignedIntN(N: 16)) {
442 BaseAddr = Addr->getOperand(i: 1);
443 SignedOffset = OffsetValue.getSExtValue();
444 }
445 }
446 }
447
448 // Unaligned memory access
449 if ((!MMO->getSize().hasValue() ||
450 MMO->getAlign() < MMO->getSize().getValue()) &&
451 !STI.systemSupportsUnalignedAccess()) {
452 if (MMO->getSize() != 4 || !isRegInGprb(Reg: I.getOperand(i: 0).getReg(), MRI))
453 return false;
454
455 unsigned LeftOffset = SignedOffset + (STI.isLittle() ? 3 : 0);
456 unsigned RightOffset = SignedOffset + (STI.isLittle() ? 0 : 3);
457 if (I.getOpcode() == G_STORE) {
458 if (!buildUnalignedStore(I, Opc: Mips::SWL, BaseAddr, Offset: LeftOffset, MMO))
459 return false;
460 if (!buildUnalignedStore(I, Opc: Mips::SWR, BaseAddr, Offset: RightOffset, MMO))
461 return false;
462 I.eraseFromParent();
463 return true;
464 }
465
466 if (I.getOpcode() == G_LOAD) {
467 Register ImplDef = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
468 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::IMPLICIT_DEF))
469 .addDef(RegNo: ImplDef);
470 Register Tmp = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
471 if (!buildUnalignedLoad(I, Opc: Mips::LWL, Dest: Tmp, BaseAddr, Offset: LeftOffset,
472 TiedDest: ImplDef, MMO))
473 return false;
474 if (!buildUnalignedLoad(I, Opc: Mips::LWR, Dest: I.getOperand(i: 0).getReg(),
475 BaseAddr, Offset: RightOffset, TiedDest: Tmp, MMO))
476 return false;
477 I.eraseFromParent();
478 return true;
479 }
480
481 return false;
482 }
483
484 const unsigned NewOpc = selectLoadStoreOpCode(I, MRI);
485 if (NewOpc == I.getOpcode())
486 return false;
487
488 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: NewOpc))
489 .add(MO: I.getOperand(i: 0))
490 .add(MO: BaseAddr)
491 .addImm(Val: SignedOffset)
492 .addMemOperand(MMO);
493 break;
494 }
495 case G_UDIV:
496 case G_UREM:
497 case G_SDIV:
498 case G_SREM: {
499 Register HILOReg = MRI.createVirtualRegister(RegClass: &Mips::ACC64RegClass);
500 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
501 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
502
503 MachineInstr *PseudoDIV, *PseudoMove;
504 PseudoDIV = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(),
505 MCID: TII.get(Opcode: IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
506 .addDef(RegNo: HILOReg)
507 .add(MO: I.getOperand(i: 1))
508 .add(MO: I.getOperand(i: 2));
509 constrainSelectedInstRegOperands(I&: *PseudoDIV, TII, TRI, RBI);
510
511 PseudoMove = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(),
512 MCID: TII.get(Opcode: IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
513 .addDef(RegNo: I.getOperand(i: 0).getReg())
514 .addUse(RegNo: HILOReg);
515 constrainSelectedInstRegOperands(I&: *PseudoMove, TII, TRI, RBI);
516
517 I.eraseFromParent();
518 return true;
519 }
520 case G_SELECT: {
521 // Handle operands with pointer type.
522 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::MOVN_I_I))
523 .add(MO: I.getOperand(i: 0))
524 .add(MO: I.getOperand(i: 2))
525 .add(MO: I.getOperand(i: 1))
526 .add(MO: I.getOperand(i: 3));
527 break;
528 }
529 case G_UNMERGE_VALUES: {
530 if (I.getNumOperands() != 3)
531 return false;
532 Register Src = I.getOperand(i: 2).getReg();
533 Register Lo = I.getOperand(i: 0).getReg();
534 Register Hi = I.getOperand(i: 1).getReg();
535 if (!isRegInFprb(Reg: Src, MRI) ||
536 !(isRegInGprb(Reg: Lo, MRI) && isRegInGprb(Reg: Hi, MRI)))
537 return false;
538
539 unsigned Opcode =
540 STI.isFP64bit() ? Mips::ExtractElementF64_64 : Mips::ExtractElementF64;
541
542 MachineInstr *ExtractLo = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
543 .addDef(RegNo: Lo)
544 .addUse(RegNo: Src)
545 .addImm(Val: 0);
546 constrainSelectedInstRegOperands(I&: *ExtractLo, TII, TRI, RBI);
547
548 MachineInstr *ExtractHi = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
549 .addDef(RegNo: Hi)
550 .addUse(RegNo: Src)
551 .addImm(Val: 1);
552 constrainSelectedInstRegOperands(I&: *ExtractHi, TII, TRI, RBI);
553
554 I.eraseFromParent();
555 return true;
556 }
557 case G_IMPLICIT_DEF: {
558 Register Dst = I.getOperand(i: 0).getReg();
559 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::IMPLICIT_DEF))
560 .addDef(RegNo: Dst);
561
562 // Set class based on register bank, there can be fpr and gpr implicit def.
563 MRI.setRegClass(Reg: Dst, RC: getRegClassForTypeOnBank(Reg: Dst, MRI));
564 break;
565 }
566 case G_CONSTANT: {
567 MachineIRBuilder B(I);
568 if (!materialize32BitImm(DestReg: I.getOperand(i: 0).getReg(),
569 Imm: I.getOperand(i: 1).getCImm()->getValue(), B))
570 return false;
571
572 I.eraseFromParent();
573 return true;
574 }
575 case G_FCONSTANT: {
576 const APFloat &FPimm = I.getOperand(i: 1).getFPImm()->getValueAPF();
577 APInt APImm = FPimm.bitcastToAPInt();
578 unsigned Size = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits();
579
580 if (Size == 32) {
581 Register GPRReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
582 MachineIRBuilder B(I);
583 if (!materialize32BitImm(DestReg: GPRReg, Imm: APImm, B))
584 return false;
585
586 MachineInstrBuilder MTC1 =
587 B.buildInstr(Opc: Mips::MTC1, DstOps: {I.getOperand(i: 0).getReg()}, SrcOps: {GPRReg});
588 MTC1.constrainAllUses(TII, TRI, RBI);
589 }
590 if (Size == 64) {
591 Register GPRRegHigh = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
592 Register GPRRegLow = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
593 MachineIRBuilder B(I);
594 if (!materialize32BitImm(DestReg: GPRRegHigh, Imm: APImm.getHiBits(numBits: 32).trunc(width: 32), B))
595 return false;
596 if (!materialize32BitImm(DestReg: GPRRegLow, Imm: APImm.getLoBits(numBits: 32).trunc(width: 32), B))
597 return false;
598
599 MachineInstrBuilder PairF64 = B.buildInstr(
600 Opc: STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
601 DstOps: {I.getOperand(i: 0).getReg()}, SrcOps: {GPRRegLow, GPRRegHigh});
602 PairF64.constrainAllUses(TII, TRI, RBI);
603 }
604
605 I.eraseFromParent();
606 return true;
607 }
608 case G_FABS: {
609 unsigned Size = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits();
610 unsigned FABSOpcode =
611 Size == 32 ? Mips::FABS_S
612 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
613 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: FABSOpcode))
614 .add(MO: I.getOperand(i: 0))
615 .add(MO: I.getOperand(i: 1));
616 break;
617 }
618 case G_FPTOSI: {
619 unsigned FromSize = MRI.getType(Reg: I.getOperand(i: 1).getReg()).getSizeInBits();
620 unsigned ToSize = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits();
621 (void)ToSize;
622 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
623 assert((FromSize == 32 || FromSize == 64) &&
624 "Unsupported floating point size for G_FPTOSI");
625
626 unsigned Opcode;
627 if (FromSize == 32)
628 Opcode = Mips::TRUNC_W_S;
629 else
630 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
631 Register ResultInFPR = MRI.createVirtualRegister(RegClass: &Mips::FGR32RegClass);
632 MachineInstr *Trunc = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
633 .addDef(RegNo: ResultInFPR)
634 .addUse(RegNo: I.getOperand(i: 1).getReg());
635 constrainSelectedInstRegOperands(I&: *Trunc, TII, TRI, RBI);
636
637 MachineInstr *Move = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::MFC1))
638 .addDef(RegNo: I.getOperand(i: 0).getReg())
639 .addUse(RegNo: ResultInFPR);
640 constrainSelectedInstRegOperands(I&: *Move, TII, TRI, RBI);
641
642 I.eraseFromParent();
643 return true;
644 }
645 case G_GLOBAL_VALUE: {
646 const llvm::GlobalValue *GVal = I.getOperand(i: 1).getGlobal();
647 if (MF.getTarget().isPositionIndependent()) {
648 MachineInstr *LWGOT = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LW))
649 .addDef(RegNo: I.getOperand(i: 0).getReg())
650 .addReg(RegNo: MF.getInfo<MipsFunctionInfo>()
651 ->getGlobalBaseRegForGlobalISel(MF))
652 .addGlobalAddress(GV: GVal);
653 // Global Values that don't have local linkage are handled differently
654 // when they are part of call sequence. MipsCallLowering::lowerCall
655 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
656 // MO_GOT_CALL flag when Callee doesn't have local linkage.
657 if (I.getOperand(i: 1).getTargetFlags() == MipsII::MO_GOT_CALL)
658 LWGOT->getOperand(i: 2).setTargetFlags(MipsII::MO_GOT_CALL);
659 else
660 LWGOT->getOperand(i: 2).setTargetFlags(MipsII::MO_GOT);
661 LWGOT->addMemOperand(
662 MF, MO: MF.getMachineMemOperand(PtrInfo: MachinePointerInfo::getGOT(MF),
663 F: MachineMemOperand::MOLoad, Size: 4, BaseAlignment: Align(4)));
664 constrainSelectedInstRegOperands(I&: *LWGOT, TII, TRI, RBI);
665
666 if (GVal->hasLocalLinkage()) {
667 Register LWGOTDef = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
668 LWGOT->getOperand(i: 0).setReg(LWGOTDef);
669
670 MachineInstr *ADDiu =
671 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
672 .addDef(RegNo: I.getOperand(i: 0).getReg())
673 .addReg(RegNo: LWGOTDef)
674 .addGlobalAddress(GV: GVal);
675 ADDiu->getOperand(i: 2).setTargetFlags(MipsII::MO_ABS_LO);
676 constrainSelectedInstRegOperands(I&: *ADDiu, TII, TRI, RBI);
677 }
678 } else {
679 Register LUiReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
680
681 MachineInstr *LUi = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LUi))
682 .addDef(RegNo: LUiReg)
683 .addGlobalAddress(GV: GVal);
684 LUi->getOperand(i: 1).setTargetFlags(MipsII::MO_ABS_HI);
685 constrainSelectedInstRegOperands(I&: *LUi, TII, TRI, RBI);
686
687 MachineInstr *ADDiu =
688 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
689 .addDef(RegNo: I.getOperand(i: 0).getReg())
690 .addUse(RegNo: LUiReg)
691 .addGlobalAddress(GV: GVal);
692 ADDiu->getOperand(i: 2).setTargetFlags(MipsII::MO_ABS_LO);
693 constrainSelectedInstRegOperands(I&: *ADDiu, TII, TRI, RBI);
694 }
695 I.eraseFromParent();
696 return true;
697 }
698 case G_JUMP_TABLE: {
699 if (MF.getTarget().isPositionIndependent()) {
700 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LW))
701 .addDef(RegNo: I.getOperand(i: 0).getReg())
702 .addReg(RegNo: MF.getInfo<MipsFunctionInfo>()
703 ->getGlobalBaseRegForGlobalISel(MF))
704 .addJumpTableIndex(Idx: I.getOperand(i: 1).getIndex(), TargetFlags: MipsII::MO_GOT)
705 .addMemOperand(MMO: MF.getMachineMemOperand(
706 PtrInfo: MachinePointerInfo::getGOT(MF), F: MachineMemOperand::MOLoad, Size: 4,
707 BaseAlignment: Align(4)));
708 } else {
709 MI =
710 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LUi))
711 .addDef(RegNo: I.getOperand(i: 0).getReg())
712 .addJumpTableIndex(Idx: I.getOperand(i: 1).getIndex(), TargetFlags: MipsII::MO_ABS_HI);
713 }
714 break;
715 }
716 case G_ICMP: {
717 struct Instr {
718 unsigned Opcode;
719 Register Def, LHS, RHS;
720 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
721 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
722
723 bool hasImm() const {
724 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
725 return true;
726 return false;
727 }
728 };
729
730 SmallVector<struct Instr, 2> Instructions;
731 Register ICMPReg = I.getOperand(i: 0).getReg();
732 Register Temp = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
733 Register LHS = I.getOperand(i: 2).getReg();
734 Register RHS = I.getOperand(i: 3).getReg();
735 CmpInst::Predicate Cond =
736 static_cast<CmpInst::Predicate>(I.getOperand(i: 1).getPredicate());
737
738 switch (Cond) {
739 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
740 Instructions.emplace_back(Args: Mips::XOR, Args&: Temp, Args&: LHS, Args&: RHS);
741 Instructions.emplace_back(Args: Mips::SLTiu, Args&: ICMPReg, Args&: Temp, Args: 1);
742 break;
743 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
744 Instructions.emplace_back(Args: Mips::XOR, Args&: Temp, Args&: LHS, Args&: RHS);
745 Instructions.emplace_back(Args: Mips::SLTu, Args&: ICMPReg, Args: Mips::ZERO, Args&: Temp);
746 break;
747 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
748 Instructions.emplace_back(Args: Mips::SLTu, Args&: ICMPReg, Args&: RHS, Args&: LHS);
749 break;
750 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
751 Instructions.emplace_back(Args: Mips::SLTu, Args&: Temp, Args&: LHS, Args&: RHS);
752 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
753 break;
754 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
755 Instructions.emplace_back(Args: Mips::SLTu, Args&: ICMPReg, Args&: LHS, Args&: RHS);
756 break;
757 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
758 Instructions.emplace_back(Args: Mips::SLTu, Args&: Temp, Args&: RHS, Args&: LHS);
759 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
760 break;
761 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
762 Instructions.emplace_back(Args: Mips::SLT, Args&: ICMPReg, Args&: RHS, Args&: LHS);
763 break;
764 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
765 Instructions.emplace_back(Args: Mips::SLT, Args&: Temp, Args&: LHS, Args&: RHS);
766 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
767 break;
768 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
769 Instructions.emplace_back(Args: Mips::SLT, Args&: ICMPReg, Args&: LHS, Args&: RHS);
770 break;
771 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
772 Instructions.emplace_back(Args: Mips::SLT, Args&: Temp, Args&: RHS, Args&: LHS);
773 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
774 break;
775 default:
776 return false;
777 }
778
779 MachineIRBuilder B(I);
780 for (const struct Instr &Instruction : Instructions) {
781 MachineInstrBuilder MIB = B.buildInstr(
782 Opc: Instruction.Opcode, DstOps: {Instruction.Def}, SrcOps: {Instruction.LHS});
783
784 if (Instruction.hasImm())
785 MIB.addImm(Val: Instruction.RHS);
786 else
787 MIB.addUse(RegNo: Instruction.RHS);
788
789 MIB.constrainAllUses(TII, TRI, RBI);
790 }
791
792 I.eraseFromParent();
793 return true;
794 }
795 case G_FCMP: {
796 unsigned MipsFCMPCondCode;
797 bool isLogicallyNegated;
798 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
799 I.getOperand(i: 1).getPredicate())) {
800 case CmpInst::FCMP_UNO: // Unordered
801 case CmpInst::FCMP_ORD: // Ordered (OR)
802 MipsFCMPCondCode = Mips::FCOND_UN;
803 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
804 break;
805 case CmpInst::FCMP_OEQ: // Equal
806 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
807 MipsFCMPCondCode = Mips::FCOND_OEQ;
808 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
809 break;
810 case CmpInst::FCMP_UEQ: // Unordered or Equal
811 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
812 MipsFCMPCondCode = Mips::FCOND_UEQ;
813 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
814 break;
815 case CmpInst::FCMP_OLT: // Ordered or Less Than
816 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
817 MipsFCMPCondCode = Mips::FCOND_OLT;
818 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
819 break;
820 case CmpInst::FCMP_ULT: // Unordered or Less Than
821 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
822 MipsFCMPCondCode = Mips::FCOND_ULT;
823 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
824 break;
825 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
826 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
827 MipsFCMPCondCode = Mips::FCOND_OLE;
828 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
829 break;
830 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
831 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
832 MipsFCMPCondCode = Mips::FCOND_ULE;
833 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
834 break;
835 default:
836 return false;
837 }
838
839 // Default compare result in gpr register will be `true`.
840 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
841 // using MOVF_I. When orignal predicate (Cond) is logically negated
842 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
843 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
844
845 Register TrueInReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
846 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
847 .addDef(RegNo: TrueInReg)
848 .addUse(RegNo: Mips::ZERO)
849 .addImm(Val: 1);
850
851 unsigned Size = MRI.getType(Reg: I.getOperand(i: 2).getReg()).getSizeInBits();
852 unsigned FCMPOpcode =
853 Size == 32 ? Mips::FCMP_S32
854 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
855 MachineInstr *FCMP = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: FCMPOpcode))
856 .addUse(RegNo: I.getOperand(i: 2).getReg())
857 .addUse(RegNo: I.getOperand(i: 3).getReg())
858 .addImm(Val: MipsFCMPCondCode);
859 constrainSelectedInstRegOperands(I&: *FCMP, TII, TRI, RBI);
860
861 MachineInstr *Move = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: MoveOpcode))
862 .addDef(RegNo: I.getOperand(i: 0).getReg())
863 .addUse(RegNo: Mips::ZERO)
864 .addUse(RegNo: Mips::FCC0)
865 .addUse(RegNo: TrueInReg);
866 constrainSelectedInstRegOperands(I&: *Move, TII, TRI, RBI);
867
868 I.eraseFromParent();
869 return true;
870 }
871 case G_FENCE: {
872 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::SYNC)).addImm(Val: 0);
873 break;
874 }
875 case G_VASTART: {
876 MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>();
877 int FI = FuncInfo->getVarArgsFrameIndex();
878
879 Register LeaReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
880 MachineInstr *LEA_ADDiu =
881 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LEA_ADDiu))
882 .addDef(RegNo: LeaReg)
883 .addFrameIndex(Idx: FI)
884 .addImm(Val: 0);
885 constrainSelectedInstRegOperands(I&: *LEA_ADDiu, TII, TRI, RBI);
886
887 MachineInstr *Store = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::SW))
888 .addUse(RegNo: LeaReg)
889 .addUse(RegNo: I.getOperand(i: 0).getReg())
890 .addImm(Val: 0);
891 constrainSelectedInstRegOperands(I&: *Store, TII, TRI, RBI);
892
893 I.eraseFromParent();
894 return true;
895 }
896 default:
897 return false;
898 }
899
900 I.eraseFromParent();
901 constrainSelectedInstRegOperands(I&: *MI, TII, TRI, RBI);
902 return true;
903}
904
905namespace llvm {
906InstructionSelector *
907createMipsInstructionSelector(const MipsTargetMachine &TM,
908 const MipsSubtarget &Subtarget,
909 const MipsRegisterBankInfo &RBI) {
910 return new MipsInstructionSelector(TM, Subtarget, RBI);
911}
912} // end namespace llvm
913