[ARM] Better patterns for fp <> predicate vectors
[llvm-complete.git] / lib / Target / Mips / MipsInstructionSelector.cpp
blob102769895df2ef3d7cd624502e5e2deac65dce68
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 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/MipsInstPrinter.h"
15 #include "MipsMachineFunction.h"
16 #include "MipsRegisterBankInfo.h"
17 #include "MipsTargetMachine.h"
18 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
19 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
21 #define DEBUG_TYPE "mips-isel"
23 using namespace llvm;
25 namespace {
27 #define GET_GLOBALISEL_PREDICATE_BITSET
28 #include "MipsGenGlobalISel.inc"
29 #undef GET_GLOBALISEL_PREDICATE_BITSET
31 class MipsInstructionSelector : public InstructionSelector {
32 public:
33 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
34 const MipsRegisterBankInfo &RBI);
36 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
37 static const char *getName() { return DEBUG_TYPE; }
39 private:
40 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
41 bool materialize32BitImm(Register DestReg, APInt Imm,
42 MachineIRBuilder &B) const;
43 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
44 const TargetRegisterClass *
45 getRegClassForTypeOnBank(unsigned OpSize, const RegisterBank &RB,
46 const RegisterBankInfo &RBI) const;
48 const MipsTargetMachine &TM;
49 const MipsSubtarget &STI;
50 const MipsInstrInfo &TII;
51 const MipsRegisterInfo &TRI;
52 const MipsRegisterBankInfo &RBI;
54 #define GET_GLOBALISEL_PREDICATES_DECL
55 #include "MipsGenGlobalISel.inc"
56 #undef GET_GLOBALISEL_PREDICATES_DECL
58 #define GET_GLOBALISEL_TEMPORARIES_DECL
59 #include "MipsGenGlobalISel.inc"
60 #undef GET_GLOBALISEL_TEMPORARIES_DECL
63 } // end anonymous namespace
65 #define GET_GLOBALISEL_IMPL
66 #include "MipsGenGlobalISel.inc"
67 #undef GET_GLOBALISEL_IMPL
69 MipsInstructionSelector::MipsInstructionSelector(
70 const MipsTargetMachine &TM, const MipsSubtarget &STI,
71 const MipsRegisterBankInfo &RBI)
72 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
73 TRI(*STI.getRegisterInfo()), RBI(RBI),
75 #define GET_GLOBALISEL_PREDICATES_INIT
76 #include "MipsGenGlobalISel.inc"
77 #undef GET_GLOBALISEL_PREDICATES_INIT
78 #define GET_GLOBALISEL_TEMPORARIES_INIT
79 #include "MipsGenGlobalISel.inc"
80 #undef GET_GLOBALISEL_TEMPORARIES_INIT
84 bool MipsInstructionSelector::selectCopy(MachineInstr &I,
85 MachineRegisterInfo &MRI) const {
86 Register DstReg = I.getOperand(0).getReg();
87 if (TargetRegisterInfo::isPhysicalRegister(DstReg))
88 return true;
90 const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI);
91 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
93 const TargetRegisterClass *RC = &Mips::GPR32RegClass;
94 if (RegBank->getID() == Mips::FPRBRegBankID) {
95 if (DstSize == 32)
96 RC = &Mips::FGR32RegClass;
97 else if (DstSize == 64)
98 RC = STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass;
99 else
100 llvm_unreachable("Unsupported destination size");
102 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
103 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
104 << " operand\n");
105 return false;
107 return true;
110 const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank(
111 unsigned OpSize, const RegisterBank &RB,
112 const RegisterBankInfo &RBI) const {
113 if (RB.getID() == Mips::GPRBRegBankID)
114 return &Mips::GPR32RegClass;
116 if (RB.getID() == Mips::FPRBRegBankID)
117 return OpSize == 32
118 ? &Mips::FGR32RegClass
119 : STI.hasMips32r6() || STI.isFP64bit() ? &Mips::FGR64RegClass
120 : &Mips::AFGR64RegClass;
122 llvm_unreachable("getRegClassForTypeOnBank can't find register class.");
123 return nullptr;
126 bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm,
127 MachineIRBuilder &B) const {
128 assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
129 // Ori zero extends immediate. Used for values with zeros in high 16 bits.
130 if (Imm.getHiBits(16).isNullValue()) {
131 MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Register(Mips::ZERO)})
132 .addImm(Imm.getLoBits(16).getLimitedValue());
133 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
135 // Lui places immediate in high 16 bits and sets low 16 bits to zero.
136 if (Imm.getLoBits(16).isNullValue()) {
137 MachineInstr *Inst = B.buildInstr(Mips::LUi, {DestReg}, {})
138 .addImm(Imm.getHiBits(16).getLimitedValue());
139 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
141 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits.
142 if (Imm.isSignedIntN(16)) {
143 MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Register(Mips::ZERO)})
144 .addImm(Imm.getLoBits(16).getLimitedValue());
145 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
147 // Values that cannot be materialized with single immediate instruction.
148 Register LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass);
149 MachineInstr *LUi = B.buildInstr(Mips::LUi, {LUiReg}, {})
150 .addImm(Imm.getHiBits(16).getLimitedValue());
151 MachineInstr *ORi = B.buildInstr(Mips::ORi, {DestReg}, {LUiReg})
152 .addImm(Imm.getLoBits(16).getLimitedValue());
153 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
154 return false;
155 if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
156 return false;
157 return true;
160 /// Returning Opc indicates that we failed to select MIPS instruction opcode.
161 static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes,
162 unsigned RegBank, bool isFP64) {
163 bool isStore = Opc == TargetOpcode::G_STORE;
164 if (RegBank == Mips::GPRBRegBankID) {
165 if (isStore)
166 switch (MemSizeInBytes) {
167 case 4:
168 return Mips::SW;
169 case 2:
170 return Mips::SH;
171 case 1:
172 return Mips::SB;
173 default:
174 return Opc;
176 else
177 // Unspecified extending load is selected into zeroExtending load.
178 switch (MemSizeInBytes) {
179 case 4:
180 return Mips::LW;
181 case 2:
182 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
183 case 1:
184 return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
185 default:
186 return Opc;
190 if (RegBank == Mips::FPRBRegBankID) {
191 switch (MemSizeInBytes) {
192 case 4:
193 return isStore ? Mips::SWC1 : Mips::LWC1;
194 case 8:
195 if (isFP64)
196 return isStore ? Mips::SDC164 : Mips::LDC164;
197 else
198 return isStore ? Mips::SDC1 : Mips::LDC1;
199 default:
200 return Opc;
203 return Opc;
206 bool MipsInstructionSelector::select(MachineInstr &I,
207 CodeGenCoverage &CoverageInfo) const {
209 MachineBasicBlock &MBB = *I.getParent();
210 MachineFunction &MF = *MBB.getParent();
211 MachineRegisterInfo &MRI = MF.getRegInfo();
213 if (!isPreISelGenericOpcode(I.getOpcode())) {
214 if (I.isCopy())
215 return selectCopy(I, MRI);
217 return true;
220 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);
230 I.eraseFromParent();
231 return true;
234 if (selectImpl(I, CoverageInfo))
235 return true;
237 MachineInstr *MI = nullptr;
238 using namespace TargetOpcode;
240 switch (I.getOpcode()) {
241 case G_UMULH: {
242 Register PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
243 MachineInstr *PseudoMULTu, *PseudoMove;
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;
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;
258 I.eraseFromParent();
259 return true;
261 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;
268 case G_INTTOPTR:
269 case G_PTRTOINT: {
270 I.setDesc(TII.get(COPY));
271 return selectCopy(I, MRI);
273 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;
280 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;
287 case G_PHI: {
288 const Register DestReg = I.getOperand(0).getReg();
289 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
291 const TargetRegisterClass *DefRC = nullptr;
292 if (TargetRegisterInfo::isPhysicalRegister(DestReg))
293 DefRC = TRI.getRegClass(DestReg);
294 else
295 DefRC = getRegClassForTypeOnBank(OpSize,
296 *RBI.getRegBank(DestReg, MRI, TRI), RBI);
298 I.setDesc(TII.get(TargetOpcode::PHI));
299 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
301 case G_STORE:
302 case G_LOAD:
303 case G_ZEXTLOAD:
304 case G_SEXTLOAD: {
305 const Register DestReg = I.getOperand(0).getReg();
306 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
307 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
308 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
310 if (DestRegBank == Mips::GPRBRegBankID && OpSize != 32)
311 return false;
313 if (DestRegBank == Mips::FPRBRegBankID && OpSize != 32 && OpSize != 64)
314 return false;
316 const unsigned NewOpc = selectLoadStoreOpCode(
317 I.getOpcode(), OpMemSizeInBytes, DestRegBank, STI.isFP64bit());
318 if (NewOpc == I.getOpcode())
319 return false;
321 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
322 .add(I.getOperand(0))
323 .add(I.getOperand(1))
324 .addImm(0)
325 .addMemOperand(*I.memoperands_begin());
326 break;
328 case G_UDIV:
329 case G_UREM:
330 case G_SDIV:
331 case G_SREM: {
332 Register HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
333 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
334 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
336 MachineInstr *PseudoDIV, *PseudoMove;
337 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
338 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
339 .addDef(HILOReg)
340 .add(I.getOperand(1))
341 .add(I.getOperand(2));
342 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
343 return false;
345 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
346 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
347 .addDef(I.getOperand(0).getReg())
348 .addUse(HILOReg);
349 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
350 return false;
352 I.eraseFromParent();
353 return true;
355 case G_SELECT: {
356 // Handle operands with pointer type.
357 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
358 .add(I.getOperand(0))
359 .add(I.getOperand(2))
360 .add(I.getOperand(1))
361 .add(I.getOperand(3));
362 break;
364 case G_CONSTANT: {
365 MachineIRBuilder B(I);
366 if (!materialize32BitImm(I.getOperand(0).getReg(),
367 I.getOperand(1).getCImm()->getValue(), B))
368 return false;
370 I.eraseFromParent();
371 return true;
373 case G_FCONSTANT: {
374 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
375 APInt APImm = FPimm.bitcastToAPInt();
376 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
378 if (Size == 32) {
379 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
380 MachineIRBuilder B(I);
381 if (!materialize32BitImm(GPRReg, APImm, B))
382 return false;
384 MachineInstrBuilder MTC1 =
385 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
386 if (!MTC1.constrainAllUses(TII, TRI, RBI))
387 return false;
389 if (Size == 64) {
390 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
391 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
392 MachineIRBuilder B(I);
393 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
394 return false;
395 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
396 return false;
398 MachineInstrBuilder PairF64 = B.buildInstr(
399 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
400 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
401 if (!PairF64.constrainAllUses(TII, TRI, RBI))
402 return false;
405 I.eraseFromParent();
406 return true;
408 case G_FABS: {
409 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
410 unsigned FABSOpcode =
411 Size == 32 ? Mips::FABS_S
412 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
413 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode))
414 .add(I.getOperand(0))
415 .add(I.getOperand(1));
416 break;
418 case G_FPTOSI: {
419 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits();
420 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
421 (void)ToSize;
422 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
423 assert((FromSize == 32 || FromSize == 64) &&
424 "Unsupported floating point size for G_FPTOSI");
426 unsigned Opcode;
427 if (FromSize == 32)
428 Opcode = Mips::TRUNC_W_S;
429 else
430 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
431 unsigned ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass);
432 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
433 .addDef(ResultInFPR)
434 .addUse(I.getOperand(1).getReg());
435 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI))
436 return false;
438 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1))
439 .addDef(I.getOperand(0).getReg())
440 .addUse(ResultInFPR);
441 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
442 return false;
444 I.eraseFromParent();
445 return true;
447 case G_GLOBAL_VALUE: {
448 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
449 if (MF.getTarget().isPositionIndependent()) {
450 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
451 .addDef(I.getOperand(0).getReg())
452 .addReg(MF.getInfo<MipsFunctionInfo>()
453 ->getGlobalBaseRegForGlobalISel())
454 .addGlobalAddress(GVal);
455 // Global Values that don't have local linkage are handled differently
456 // when they are part of call sequence. MipsCallLowering::lowerCall
457 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
458 // MO_GOT_CALL flag when Callee doesn't have local linkage.
459 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL)
460 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL);
461 else
462 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT);
463 LWGOT->addMemOperand(
464 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
465 MachineMemOperand::MOLoad, 4, 4));
466 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI))
467 return false;
469 if (GVal->hasLocalLinkage()) {
470 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass);
471 LWGOT->getOperand(0).setReg(LWGOTDef);
473 MachineInstr *ADDiu =
474 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
475 .addDef(I.getOperand(0).getReg())
476 .addReg(LWGOTDef)
477 .addGlobalAddress(GVal);
478 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
479 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
480 return false;
482 } else {
483 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
485 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
486 .addDef(LUiReg)
487 .addGlobalAddress(GVal);
488 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
489 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
490 return false;
492 MachineInstr *ADDiu =
493 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
494 .addDef(I.getOperand(0).getReg())
495 .addUse(LUiReg)
496 .addGlobalAddress(GVal);
497 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
498 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
499 return false;
501 I.eraseFromParent();
502 return true;
504 case G_ICMP: {
505 struct Instr {
506 unsigned Opcode;
507 Register Def, LHS, RHS;
508 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
509 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
511 bool hasImm() const {
512 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
513 return true;
514 return false;
518 SmallVector<struct Instr, 2> Instructions;
519 Register ICMPReg = I.getOperand(0).getReg();
520 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
521 Register LHS = I.getOperand(2).getReg();
522 Register RHS = I.getOperand(3).getReg();
523 CmpInst::Predicate Cond =
524 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
526 switch (Cond) {
527 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
528 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
529 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
530 break;
531 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
532 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
533 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
534 break;
535 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
536 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
537 break;
538 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
539 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
540 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
541 break;
542 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
543 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
544 break;
545 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
546 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
547 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
548 break;
549 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
550 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
551 break;
552 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
553 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
554 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
555 break;
556 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
557 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
558 break;
559 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
560 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
561 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
562 break;
563 default:
564 return false;
567 MachineIRBuilder B(I);
568 for (const struct Instr &Instruction : Instructions) {
569 MachineInstrBuilder MIB = B.buildInstr(
570 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
572 if (Instruction.hasImm())
573 MIB.addImm(Instruction.RHS);
574 else
575 MIB.addUse(Instruction.RHS);
577 if (!MIB.constrainAllUses(TII, TRI, RBI))
578 return false;
581 I.eraseFromParent();
582 return true;
584 case G_FCMP: {
585 unsigned MipsFCMPCondCode;
586 bool isLogicallyNegated;
587 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
588 I.getOperand(1).getPredicate())) {
589 case CmpInst::FCMP_UNO: // Unordered
590 case CmpInst::FCMP_ORD: // Ordered (OR)
591 MipsFCMPCondCode = Mips::FCOND_UN;
592 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
593 break;
594 case CmpInst::FCMP_OEQ: // Equal
595 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
596 MipsFCMPCondCode = Mips::FCOND_OEQ;
597 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
598 break;
599 case CmpInst::FCMP_UEQ: // Unordered or Equal
600 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
601 MipsFCMPCondCode = Mips::FCOND_UEQ;
602 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
603 break;
604 case CmpInst::FCMP_OLT: // Ordered or Less Than
605 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
606 MipsFCMPCondCode = Mips::FCOND_OLT;
607 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
608 break;
609 case CmpInst::FCMP_ULT: // Unordered or Less Than
610 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
611 MipsFCMPCondCode = Mips::FCOND_ULT;
612 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
613 break;
614 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
615 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
616 MipsFCMPCondCode = Mips::FCOND_OLE;
617 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
618 break;
619 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
620 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
621 MipsFCMPCondCode = Mips::FCOND_ULE;
622 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
623 break;
624 default:
625 return false;
628 // Default compare result in gpr register will be `true`.
629 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
630 // using MOVF_I. When orignal predicate (Cond) is logically negated
631 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
632 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
634 unsigned TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
635 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
636 .addDef(TrueInReg)
637 .addUse(Mips::ZERO)
638 .addImm(1);
640 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
641 unsigned FCMPOpcode =
642 Size == 32 ? Mips::FCMP_S32
643 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
644 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode))
645 .addUse(I.getOperand(2).getReg())
646 .addUse(I.getOperand(3).getReg())
647 .addImm(MipsFCMPCondCode);
648 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI))
649 return false;
651 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode))
652 .addDef(I.getOperand(0).getReg())
653 .addUse(Mips::ZERO)
654 .addUse(Mips::FCC0)
655 .addUse(TrueInReg);
656 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
657 return false;
659 I.eraseFromParent();
660 return true;
662 default:
663 return false;
666 I.eraseFromParent();
667 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
670 namespace llvm {
671 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
672 MipsSubtarget &Subtarget,
673 MipsRegisterBankInfo &RBI) {
674 return new MipsInstructionSelector(TM, Subtarget, RBI);
676 } // end namespace llvm