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_BRINDIRECT: {
411 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::PseudoIndirectBranch))
412 .add(MO: I.getOperand(i: 0));
413 break;
414 }
415 case G_PHI: {
416 const Register DestReg = I.getOperand(i: 0).getReg();
417
418 const TargetRegisterClass *DefRC = nullptr;
419 if (DestReg.isPhysical())
420 DefRC = TRI.getRegClass(i: DestReg);
421 else
422 DefRC = getRegClassForTypeOnBank(Reg: DestReg, MRI);
423
424 I.setDesc(TII.get(Opcode: TargetOpcode::PHI));
425 return RBI.constrainGenericRegister(Reg: DestReg, RC: *DefRC, MRI);
426 }
427 case G_STORE:
428 case G_LOAD:
429 case G_ZEXTLOAD:
430 case G_SEXTLOAD: {
431 auto MMO = *I.memoperands_begin();
432 MachineOperand BaseAddr = I.getOperand(i: 1);
433 int64_t SignedOffset = 0;
434 // Try to fold load/store + G_PTR_ADD + G_CONSTANT
435 // %SignedOffset:(s32) = G_CONSTANT i32 16_bit_signed_immediate
436 // %Addr:(p0) = G_PTR_ADD %BaseAddr, %SignedOffset
437 // %LoadResult/%StoreSrc = load/store %Addr(p0)
438 // into:
439 // %LoadResult/%StoreSrc = NewOpc %BaseAddr(p0), 16_bit_signed_immediate
440
441 MachineInstr *Addr = MRI.getVRegDef(Reg: I.getOperand(i: 1).getReg());
442 if (Addr->getOpcode() == G_PTR_ADD) {
443 MachineInstr *Offset = MRI.getVRegDef(Reg: Addr->getOperand(i: 2).getReg());
444 if (Offset->getOpcode() == G_CONSTANT) {
445 APInt OffsetValue = Offset->getOperand(i: 1).getCImm()->getValue();
446 if (OffsetValue.isSignedIntN(N: 16)) {
447 BaseAddr = Addr->getOperand(i: 1);
448 SignedOffset = OffsetValue.getSExtValue();
449 }
450 }
451 }
452
453 // Unaligned memory access
454 if ((!MMO->getSize().hasValue() ||
455 MMO->getAlign() < MMO->getSize().getValue()) &&
456 !STI.systemSupportsUnalignedAccess()) {
457 if (MMO->getSize() != 4 || !isRegInGprb(Reg: I.getOperand(i: 0).getReg(), MRI))
458 return false;
459
460 if (I.getOpcode() == G_STORE) {
461 if (!buildUnalignedStore(I, Opc: Mips::SWL, BaseAddr, Offset: SignedOffset + 3, MMO))
462 return false;
463 if (!buildUnalignedStore(I, Opc: Mips::SWR, BaseAddr, Offset: SignedOffset, MMO))
464 return false;
465 I.eraseFromParent();
466 return true;
467 }
468
469 if (I.getOpcode() == G_LOAD) {
470 Register ImplDef = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
471 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::IMPLICIT_DEF))
472 .addDef(RegNo: ImplDef);
473 Register Tmp = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
474 if (!buildUnalignedLoad(I, Opc: Mips::LWL, Dest: Tmp, BaseAddr, Offset: SignedOffset + 3,
475 TiedDest: ImplDef, MMO))
476 return false;
477 if (!buildUnalignedLoad(I, Opc: Mips::LWR, Dest: I.getOperand(i: 0).getReg(),
478 BaseAddr, Offset: SignedOffset, TiedDest: Tmp, MMO))
479 return false;
480 I.eraseFromParent();
481 return true;
482 }
483
484 return false;
485 }
486
487 const unsigned NewOpc = selectLoadStoreOpCode(I, MRI);
488 if (NewOpc == I.getOpcode())
489 return false;
490
491 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: NewOpc))
492 .add(MO: I.getOperand(i: 0))
493 .add(MO: BaseAddr)
494 .addImm(Val: SignedOffset)
495 .addMemOperand(MMO);
496 break;
497 }
498 case G_UDIV:
499 case G_UREM:
500 case G_SDIV:
501 case G_SREM: {
502 Register HILOReg = MRI.createVirtualRegister(RegClass: &Mips::ACC64RegClass);
503 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
504 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
505
506 MachineInstr *PseudoDIV, *PseudoMove;
507 PseudoDIV = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(),
508 MCID: TII.get(Opcode: IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
509 .addDef(RegNo: HILOReg)
510 .add(MO: I.getOperand(i: 1))
511 .add(MO: I.getOperand(i: 2));
512 constrainSelectedInstRegOperands(I&: *PseudoDIV, TII, TRI, RBI);
513
514 PseudoMove = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(),
515 MCID: TII.get(Opcode: IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
516 .addDef(RegNo: I.getOperand(i: 0).getReg())
517 .addUse(RegNo: HILOReg);
518 constrainSelectedInstRegOperands(I&: *PseudoMove, TII, TRI, RBI);
519
520 I.eraseFromParent();
521 return true;
522 }
523 case G_SELECT: {
524 // Handle operands with pointer type.
525 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::MOVN_I_I))
526 .add(MO: I.getOperand(i: 0))
527 .add(MO: I.getOperand(i: 2))
528 .add(MO: I.getOperand(i: 1))
529 .add(MO: I.getOperand(i: 3));
530 break;
531 }
532 case G_UNMERGE_VALUES: {
533 if (I.getNumOperands() != 3)
534 return false;
535 Register Src = I.getOperand(i: 2).getReg();
536 Register Lo = I.getOperand(i: 0).getReg();
537 Register Hi = I.getOperand(i: 1).getReg();
538 if (!isRegInFprb(Reg: Src, MRI) ||
539 !(isRegInGprb(Reg: Lo, MRI) && isRegInGprb(Reg: Hi, MRI)))
540 return false;
541
542 unsigned Opcode =
543 STI.isFP64bit() ? Mips::ExtractElementF64_64 : Mips::ExtractElementF64;
544
545 MachineInstr *ExtractLo = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
546 .addDef(RegNo: Lo)
547 .addUse(RegNo: Src)
548 .addImm(Val: 0);
549 constrainSelectedInstRegOperands(I&: *ExtractLo, TII, TRI, RBI);
550
551 MachineInstr *ExtractHi = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
552 .addDef(RegNo: Hi)
553 .addUse(RegNo: Src)
554 .addImm(Val: 1);
555 constrainSelectedInstRegOperands(I&: *ExtractHi, TII, TRI, RBI);
556
557 I.eraseFromParent();
558 return true;
559 }
560 case G_IMPLICIT_DEF: {
561 Register Dst = I.getOperand(i: 0).getReg();
562 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::IMPLICIT_DEF))
563 .addDef(RegNo: Dst);
564
565 // Set class based on register bank, there can be fpr and gpr implicit def.
566 MRI.setRegClass(Reg: Dst, RC: getRegClassForTypeOnBank(Reg: Dst, MRI));
567 break;
568 }
569 case G_CONSTANT: {
570 MachineIRBuilder B(I);
571 if (!materialize32BitImm(DestReg: I.getOperand(i: 0).getReg(),
572 Imm: I.getOperand(i: 1).getCImm()->getValue(), B))
573 return false;
574
575 I.eraseFromParent();
576 return true;
577 }
578 case G_FCONSTANT: {
579 const APFloat &FPimm = I.getOperand(i: 1).getFPImm()->getValueAPF();
580 APInt APImm = FPimm.bitcastToAPInt();
581 unsigned Size = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits();
582
583 if (Size == 32) {
584 Register GPRReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
585 MachineIRBuilder B(I);
586 if (!materialize32BitImm(DestReg: GPRReg, Imm: APImm, B))
587 return false;
588
589 MachineInstrBuilder MTC1 =
590 B.buildInstr(Opc: Mips::MTC1, DstOps: {I.getOperand(i: 0).getReg()}, SrcOps: {GPRReg});
591 MTC1.constrainAllUses(TII, TRI, RBI);
592 }
593 if (Size == 64) {
594 Register GPRRegHigh = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
595 Register GPRRegLow = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
596 MachineIRBuilder B(I);
597 if (!materialize32BitImm(DestReg: GPRRegHigh, Imm: APImm.getHiBits(numBits: 32).trunc(width: 32), B))
598 return false;
599 if (!materialize32BitImm(DestReg: GPRRegLow, Imm: APImm.getLoBits(numBits: 32).trunc(width: 32), B))
600 return false;
601
602 MachineInstrBuilder PairF64 = B.buildInstr(
603 Opc: STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
604 DstOps: {I.getOperand(i: 0).getReg()}, SrcOps: {GPRRegLow, GPRRegHigh});
605 PairF64.constrainAllUses(TII, TRI, RBI);
606 }
607
608 I.eraseFromParent();
609 return true;
610 }
611 case G_FABS: {
612 unsigned Size = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits();
613 unsigned FABSOpcode =
614 Size == 32 ? Mips::FABS_S
615 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
616 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: FABSOpcode))
617 .add(MO: I.getOperand(i: 0))
618 .add(MO: I.getOperand(i: 1));
619 break;
620 }
621 case G_FPTOSI: {
622 unsigned FromSize = MRI.getType(Reg: I.getOperand(i: 1).getReg()).getSizeInBits();
623 unsigned ToSize = MRI.getType(Reg: I.getOperand(i: 0).getReg()).getSizeInBits();
624 (void)ToSize;
625 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
626 assert((FromSize == 32 || FromSize == 64) &&
627 "Unsupported floating point size for G_FPTOSI");
628
629 unsigned Opcode;
630 if (FromSize == 32)
631 Opcode = Mips::TRUNC_W_S;
632 else
633 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
634 Register ResultInFPR = MRI.createVirtualRegister(RegClass: &Mips::FGR32RegClass);
635 MachineInstr *Trunc = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
636 .addDef(RegNo: ResultInFPR)
637 .addUse(RegNo: I.getOperand(i: 1).getReg());
638 constrainSelectedInstRegOperands(I&: *Trunc, TII, TRI, RBI);
639
640 MachineInstr *Move = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::MFC1))
641 .addDef(RegNo: I.getOperand(i: 0).getReg())
642 .addUse(RegNo: ResultInFPR);
643 constrainSelectedInstRegOperands(I&: *Move, TII, TRI, RBI);
644
645 I.eraseFromParent();
646 return true;
647 }
648 case G_GLOBAL_VALUE: {
649 const llvm::GlobalValue *GVal = I.getOperand(i: 1).getGlobal();
650 if (MF.getTarget().isPositionIndependent()) {
651 MachineInstr *LWGOT = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LW))
652 .addDef(RegNo: I.getOperand(i: 0).getReg())
653 .addReg(RegNo: MF.getInfo<MipsFunctionInfo>()
654 ->getGlobalBaseRegForGlobalISel(MF))
655 .addGlobalAddress(GV: GVal);
656 // Global Values that don't have local linkage are handled differently
657 // when they are part of call sequence. MipsCallLowering::lowerCall
658 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
659 // MO_GOT_CALL flag when Callee doesn't have local linkage.
660 if (I.getOperand(i: 1).getTargetFlags() == MipsII::MO_GOT_CALL)
661 LWGOT->getOperand(i: 2).setTargetFlags(MipsII::MO_GOT_CALL);
662 else
663 LWGOT->getOperand(i: 2).setTargetFlags(MipsII::MO_GOT);
664 LWGOT->addMemOperand(
665 MF, MO: MF.getMachineMemOperand(PtrInfo: MachinePointerInfo::getGOT(MF),
666 F: MachineMemOperand::MOLoad, Size: 4, BaseAlignment: Align(4)));
667 constrainSelectedInstRegOperands(I&: *LWGOT, TII, TRI, RBI);
668
669 if (GVal->hasLocalLinkage()) {
670 Register LWGOTDef = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
671 LWGOT->getOperand(i: 0).setReg(LWGOTDef);
672
673 MachineInstr *ADDiu =
674 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
675 .addDef(RegNo: I.getOperand(i: 0).getReg())
676 .addReg(RegNo: LWGOTDef)
677 .addGlobalAddress(GV: GVal);
678 ADDiu->getOperand(i: 2).setTargetFlags(MipsII::MO_ABS_LO);
679 constrainSelectedInstRegOperands(I&: *ADDiu, TII, TRI, RBI);
680 }
681 } else {
682 Register LUiReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
683
684 MachineInstr *LUi = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LUi))
685 .addDef(RegNo: LUiReg)
686 .addGlobalAddress(GV: GVal);
687 LUi->getOperand(i: 1).setTargetFlags(MipsII::MO_ABS_HI);
688 constrainSelectedInstRegOperands(I&: *LUi, TII, TRI, RBI);
689
690 MachineInstr *ADDiu =
691 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
692 .addDef(RegNo: I.getOperand(i: 0).getReg())
693 .addUse(RegNo: LUiReg)
694 .addGlobalAddress(GV: GVal);
695 ADDiu->getOperand(i: 2).setTargetFlags(MipsII::MO_ABS_LO);
696 constrainSelectedInstRegOperands(I&: *ADDiu, TII, TRI, RBI);
697 }
698 I.eraseFromParent();
699 return true;
700 }
701 case G_JUMP_TABLE: {
702 if (MF.getTarget().isPositionIndependent()) {
703 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LW))
704 .addDef(RegNo: I.getOperand(i: 0).getReg())
705 .addReg(RegNo: MF.getInfo<MipsFunctionInfo>()
706 ->getGlobalBaseRegForGlobalISel(MF))
707 .addJumpTableIndex(Idx: I.getOperand(i: 1).getIndex(), TargetFlags: MipsII::MO_GOT)
708 .addMemOperand(MMO: MF.getMachineMemOperand(
709 PtrInfo: MachinePointerInfo::getGOT(MF), F: MachineMemOperand::MOLoad, Size: 4,
710 BaseAlignment: Align(4)));
711 } else {
712 MI =
713 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LUi))
714 .addDef(RegNo: I.getOperand(i: 0).getReg())
715 .addJumpTableIndex(Idx: I.getOperand(i: 1).getIndex(), TargetFlags: MipsII::MO_ABS_HI);
716 }
717 break;
718 }
719 case G_ICMP: {
720 struct Instr {
721 unsigned Opcode;
722 Register Def, LHS, RHS;
723 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
724 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
725
726 bool hasImm() const {
727 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
728 return true;
729 return false;
730 }
731 };
732
733 SmallVector<struct Instr, 2> Instructions;
734 Register ICMPReg = I.getOperand(i: 0).getReg();
735 Register Temp = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
736 Register LHS = I.getOperand(i: 2).getReg();
737 Register RHS = I.getOperand(i: 3).getReg();
738 CmpInst::Predicate Cond =
739 static_cast<CmpInst::Predicate>(I.getOperand(i: 1).getPredicate());
740
741 switch (Cond) {
742 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
743 Instructions.emplace_back(Args: Mips::XOR, Args&: Temp, Args&: LHS, Args&: RHS);
744 Instructions.emplace_back(Args: Mips::SLTiu, Args&: ICMPReg, Args&: Temp, Args: 1);
745 break;
746 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
747 Instructions.emplace_back(Args: Mips::XOR, Args&: Temp, Args&: LHS, Args&: RHS);
748 Instructions.emplace_back(Args: Mips::SLTu, Args&: ICMPReg, Args: Mips::ZERO, Args&: Temp);
749 break;
750 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
751 Instructions.emplace_back(Args: Mips::SLTu, Args&: ICMPReg, Args&: RHS, Args&: LHS);
752 break;
753 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
754 Instructions.emplace_back(Args: Mips::SLTu, Args&: Temp, Args&: LHS, Args&: RHS);
755 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
756 break;
757 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
758 Instructions.emplace_back(Args: Mips::SLTu, Args&: ICMPReg, Args&: LHS, Args&: RHS);
759 break;
760 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
761 Instructions.emplace_back(Args: Mips::SLTu, Args&: Temp, Args&: RHS, Args&: LHS);
762 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
763 break;
764 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
765 Instructions.emplace_back(Args: Mips::SLT, Args&: ICMPReg, Args&: RHS, Args&: LHS);
766 break;
767 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
768 Instructions.emplace_back(Args: Mips::SLT, Args&: Temp, Args&: LHS, Args&: RHS);
769 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
770 break;
771 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
772 Instructions.emplace_back(Args: Mips::SLT, Args&: ICMPReg, Args&: LHS, Args&: RHS);
773 break;
774 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
775 Instructions.emplace_back(Args: Mips::SLT, Args&: Temp, Args&: RHS, Args&: LHS);
776 Instructions.emplace_back(Args: Mips::XORi, Args&: ICMPReg, Args&: Temp, Args: 1);
777 break;
778 default:
779 return false;
780 }
781
782 MachineIRBuilder B(I);
783 for (const struct Instr &Instruction : Instructions) {
784 MachineInstrBuilder MIB = B.buildInstr(
785 Opc: Instruction.Opcode, DstOps: {Instruction.Def}, SrcOps: {Instruction.LHS});
786
787 if (Instruction.hasImm())
788 MIB.addImm(Val: Instruction.RHS);
789 else
790 MIB.addUse(RegNo: Instruction.RHS);
791
792 MIB.constrainAllUses(TII, TRI, RBI);
793 }
794
795 I.eraseFromParent();
796 return true;
797 }
798 case G_FCMP: {
799 unsigned MipsFCMPCondCode;
800 bool isLogicallyNegated;
801 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
802 I.getOperand(i: 1).getPredicate())) {
803 case CmpInst::FCMP_UNO: // Unordered
804 case CmpInst::FCMP_ORD: // Ordered (OR)
805 MipsFCMPCondCode = Mips::FCOND_UN;
806 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
807 break;
808 case CmpInst::FCMP_OEQ: // Equal
809 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
810 MipsFCMPCondCode = Mips::FCOND_OEQ;
811 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
812 break;
813 case CmpInst::FCMP_UEQ: // Unordered or Equal
814 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
815 MipsFCMPCondCode = Mips::FCOND_UEQ;
816 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
817 break;
818 case CmpInst::FCMP_OLT: // Ordered or Less Than
819 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
820 MipsFCMPCondCode = Mips::FCOND_OLT;
821 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
822 break;
823 case CmpInst::FCMP_ULT: // Unordered or Less Than
824 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
825 MipsFCMPCondCode = Mips::FCOND_ULT;
826 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
827 break;
828 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
829 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
830 MipsFCMPCondCode = Mips::FCOND_OLE;
831 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
832 break;
833 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
834 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
835 MipsFCMPCondCode = Mips::FCOND_ULE;
836 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
837 break;
838 default:
839 return false;
840 }
841
842 // Default compare result in gpr register will be `true`.
843 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
844 // using MOVF_I. When orignal predicate (Cond) is logically negated
845 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
846 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
847
848 Register TrueInReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
849 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::ADDiu))
850 .addDef(RegNo: TrueInReg)
851 .addUse(RegNo: Mips::ZERO)
852 .addImm(Val: 1);
853
854 unsigned Size = MRI.getType(Reg: I.getOperand(i: 2).getReg()).getSizeInBits();
855 unsigned FCMPOpcode =
856 Size == 32 ? Mips::FCMP_S32
857 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
858 MachineInstr *FCMP = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: FCMPOpcode))
859 .addUse(RegNo: I.getOperand(i: 2).getReg())
860 .addUse(RegNo: I.getOperand(i: 3).getReg())
861 .addImm(Val: MipsFCMPCondCode);
862 constrainSelectedInstRegOperands(I&: *FCMP, TII, TRI, RBI);
863
864 MachineInstr *Move = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: MoveOpcode))
865 .addDef(RegNo: I.getOperand(i: 0).getReg())
866 .addUse(RegNo: Mips::ZERO)
867 .addUse(RegNo: Mips::FCC0)
868 .addUse(RegNo: TrueInReg);
869 constrainSelectedInstRegOperands(I&: *Move, TII, TRI, RBI);
870
871 I.eraseFromParent();
872 return true;
873 }
874 case G_FENCE: {
875 MI = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::SYNC)).addImm(Val: 0);
876 break;
877 }
878 case G_VASTART: {
879 MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>();
880 int FI = FuncInfo->getVarArgsFrameIndex();
881
882 Register LeaReg = MRI.createVirtualRegister(RegClass: &Mips::GPR32RegClass);
883 MachineInstr *LEA_ADDiu =
884 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::LEA_ADDiu))
885 .addDef(RegNo: LeaReg)
886 .addFrameIndex(Idx: FI)
887 .addImm(Val: 0);
888 constrainSelectedInstRegOperands(I&: *LEA_ADDiu, TII, TRI, RBI);
889
890 MachineInstr *Store = BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Mips::SW))
891 .addUse(RegNo: LeaReg)
892 .addUse(RegNo: I.getOperand(i: 0).getReg())
893 .addImm(Val: 0);
894 constrainSelectedInstRegOperands(I&: *Store, TII, TRI, RBI);
895
896 I.eraseFromParent();
897 return true;
898 }
899 default:
900 return false;
901 }
902
903 I.eraseFromParent();
904 constrainSelectedInstRegOperands(I&: *MI, TII, TRI, RBI);
905 return true;
906}
907
908namespace llvm {
909InstructionSelector *
910createMipsInstructionSelector(const MipsTargetMachine &TM,
911 const MipsSubtarget &Subtarget,
912 const MipsRegisterBankInfo &RBI) {
913 return new MipsInstructionSelector(TM, Subtarget, RBI);
914}
915} // end namespace llvm
916