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 "MipsRegisterBankInfo.h"
15 #include "MipsTargetMachine.h"
16 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
17 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
18 
19 #define DEBUG_TYPE "mips-isel"
20 
21 using namespace llvm;
22 
23 namespace {
24 
25 #define GET_GLOBALISEL_PREDICATE_BITSET
26 #include "MipsGenGlobalISel.inc"
27 #undef GET_GLOBALISEL_PREDICATE_BITSET
28 
29 class MipsInstructionSelector : public InstructionSelector {
30 public:
31   MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
32                           const MipsRegisterBankInfo &RBI);
33 
34   bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
35   static const char *getName() { return DEBUG_TYPE; }
36 
37 private:
38   bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
39   bool materialize32BitImm(unsigned DestReg, APInt Imm,
40                            MachineIRBuilder &B) const;
41   bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
42 
43   const MipsTargetMachine &TM;
44   const MipsSubtarget &STI;
45   const MipsInstrInfo &TII;
46   const MipsRegisterInfo &TRI;
47   const MipsRegisterBankInfo &RBI;
48 
49 #define GET_GLOBALISEL_PREDICATES_DECL
50 #include "MipsGenGlobalISel.inc"
51 #undef GET_GLOBALISEL_PREDICATES_DECL
52 
53 #define GET_GLOBALISEL_TEMPORARIES_DECL
54 #include "MipsGenGlobalISel.inc"
55 #undef GET_GLOBALISEL_TEMPORARIES_DECL
56 };
57 
58 } // end anonymous namespace
59 
60 #define GET_GLOBALISEL_IMPL
61 #include "MipsGenGlobalISel.inc"
62 #undef GET_GLOBALISEL_IMPL
63 
64 MipsInstructionSelector::MipsInstructionSelector(
65     const MipsTargetMachine &TM, const MipsSubtarget &STI,
66     const MipsRegisterBankInfo &RBI)
67     : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
68       TRI(*STI.getRegisterInfo()), RBI(RBI),
69 
70 #define GET_GLOBALISEL_PREDICATES_INIT
71 #include "MipsGenGlobalISel.inc"
72 #undef GET_GLOBALISEL_PREDICATES_INIT
73 #define GET_GLOBALISEL_TEMPORARIES_INIT
74 #include "MipsGenGlobalISel.inc"
75 #undef GET_GLOBALISEL_TEMPORARIES_INIT
76 {
77 }
78 
79 bool MipsInstructionSelector::selectCopy(MachineInstr &I,
80                                          MachineRegisterInfo &MRI) const {
81   unsigned DstReg = I.getOperand(0).getReg();
82   if (TargetRegisterInfo::isPhysicalRegister(DstReg))
83     return true;
84 
85   const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI);
86   const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
87 
88   const TargetRegisterClass *RC = &Mips::GPR32RegClass;
89   if (RegBank->getID() == Mips::FPRBRegBankID) {
90     if (DstSize == 32)
91       RC = &Mips::FGR32RegClass;
92     else if (DstSize == 64)
93       RC = STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass;
94     else
95       llvm_unreachable("Unsupported destination size");
96   }
97   if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
98     LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
99                       << " operand\n");
100     return false;
101   }
102   return true;
103 }
104 
105 bool MipsInstructionSelector::materialize32BitImm(unsigned DestReg, APInt Imm,
106                                                   MachineIRBuilder &B) const {
107   assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
108   // Ori zero extends immediate. Used for values with zeros in high 16 bits.
109   if (Imm.getHiBits(16).isNullValue()) {
110     MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Mips::ZERO})
111                              .addImm(Imm.getLoBits(16).getLimitedValue());
112     return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
113   }
114   // Lui places immediate in high 16 bits and sets low 16 bits to zero.
115   if (Imm.getLoBits(16).isNullValue()) {
116     MachineInstr *Inst = B.buildInstr(Mips::LUi, {DestReg}, {})
117                              .addImm(Imm.getHiBits(16).getLimitedValue());
118     return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
119   }
120   // ADDiu sign extends immediate. Used for values with 1s in high 17 bits.
121   if (Imm.isSignedIntN(16)) {
122     MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Mips::ZERO})
123                              .addImm(Imm.getLoBits(16).getLimitedValue());
124     return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
125   }
126   // Values that cannot be materialized with single immediate instruction.
127   unsigned LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass);
128   MachineInstr *LUi = B.buildInstr(Mips::LUi, {LUiReg}, {})
129                           .addImm(Imm.getHiBits(16).getLimitedValue());
130   MachineInstr *ORi = B.buildInstr(Mips::ORi, {DestReg}, {LUiReg})
131                           .addImm(Imm.getLoBits(16).getLimitedValue());
132   if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
133     return false;
134   if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
135     return false;
136   return true;
137 }
138 
139 /// Returning Opc indicates that we failed to select MIPS instruction opcode.
140 static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes) {
141   if (Opc == TargetOpcode::G_STORE)
142     switch (MemSizeInBytes) {
143     case 4:
144       return Mips::SW;
145     case 2:
146       return Mips::SH;
147     case 1:
148       return Mips::SB;
149     default:
150       return Opc;
151     }
152   else
153     // Unspecified extending load is selected into zeroExtending load.
154     switch (MemSizeInBytes) {
155     case 4:
156       return Mips::LW;
157     case 2:
158       return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
159     case 1:
160       return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
161     default:
162       return Opc;
163     }
164 }
165 
166 bool MipsInstructionSelector::select(MachineInstr &I,
167                                      CodeGenCoverage &CoverageInfo) const {
168 
169   MachineBasicBlock &MBB = *I.getParent();
170   MachineFunction &MF = *MBB.getParent();
171   MachineRegisterInfo &MRI = MF.getRegInfo();
172 
173   if (!isPreISelGenericOpcode(I.getOpcode())) {
174     if (I.isCopy())
175       return selectCopy(I, MRI);
176 
177     return true;
178   }
179 
180   if (I.getOpcode() == Mips::G_MUL) {
181     MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL))
182                             .add(I.getOperand(0))
183                             .add(I.getOperand(1))
184                             .add(I.getOperand(2));
185     if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI))
186       return false;
187     Mul->getOperand(3).setIsDead(true);
188     Mul->getOperand(4).setIsDead(true);
189 
190     I.eraseFromParent();
191     return true;
192   }
193 
194   if (selectImpl(I, CoverageInfo))
195     return true;
196 
197   MachineInstr *MI = nullptr;
198   using namespace TargetOpcode;
199 
200   switch (I.getOpcode()) {
201   case G_UMULH: {
202     unsigned PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
203     MachineInstr *PseudoMULTu, *PseudoMove;
204 
205     PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu))
206                       .addDef(PseudoMULTuReg)
207                       .add(I.getOperand(1))
208                       .add(I.getOperand(2));
209     if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI))
210       return false;
211 
212     PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI))
213                      .addDef(I.getOperand(0).getReg())
214                      .addUse(PseudoMULTuReg);
215     if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
216       return false;
217 
218     I.eraseFromParent();
219     return true;
220   }
221   case G_GEP: {
222     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
223              .add(I.getOperand(0))
224              .add(I.getOperand(1))
225              .add(I.getOperand(2));
226     break;
227   }
228   case G_FRAME_INDEX: {
229     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
230              .add(I.getOperand(0))
231              .add(I.getOperand(1))
232              .addImm(0);
233     break;
234   }
235   case G_BRCOND: {
236     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
237              .add(I.getOperand(0))
238              .addUse(Mips::ZERO)
239              .add(I.getOperand(1));
240     break;
241   }
242   case G_PHI: {
243     const unsigned DestReg = I.getOperand(0).getReg();
244     const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
245     const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
246 
247     if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
248       return false;
249 
250     const TargetRegisterClass *DefRC = &Mips::GPR32RegClass;
251     I.setDesc(TII.get(TargetOpcode::PHI));
252     return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
253   }
254   case G_STORE:
255   case G_LOAD:
256   case G_ZEXTLOAD:
257   case G_SEXTLOAD: {
258     const unsigned DestReg = I.getOperand(0).getReg();
259     const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
260     const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
261     const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
262 
263     if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
264       return false;
265 
266     const unsigned NewOpc =
267         selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes);
268     if (NewOpc == I.getOpcode())
269       return false;
270 
271     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
272              .add(I.getOperand(0))
273              .add(I.getOperand(1))
274              .addImm(0)
275              .addMemOperand(*I.memoperands_begin());
276     break;
277   }
278   case G_UDIV:
279   case G_UREM:
280   case G_SDIV:
281   case G_SREM: {
282     unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
283     bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
284     bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
285 
286     MachineInstr *PseudoDIV, *PseudoMove;
287     PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
288                         TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
289                     .addDef(HILOReg)
290                     .add(I.getOperand(1))
291                     .add(I.getOperand(2));
292     if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
293       return false;
294 
295     PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
296                          TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
297                      .addDef(I.getOperand(0).getReg())
298                      .addUse(HILOReg);
299     if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
300       return false;
301 
302     I.eraseFromParent();
303     return true;
304   }
305   case G_SELECT: {
306     // Handle operands with pointer type.
307     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
308              .add(I.getOperand(0))
309              .add(I.getOperand(2))
310              .add(I.getOperand(1))
311              .add(I.getOperand(3));
312     break;
313   }
314   case G_CONSTANT: {
315     MachineIRBuilder B(I);
316     if (!materialize32BitImm(I.getOperand(0).getReg(),
317                              I.getOperand(1).getCImm()->getValue(), B))
318       return false;
319 
320     I.eraseFromParent();
321     return true;
322   }
323   case G_FCONSTANT: {
324     const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
325     APInt APImm = FPimm.bitcastToAPInt();
326     unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
327 
328     if (Size == 32) {
329       unsigned GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
330       MachineIRBuilder B(I);
331       if (!materialize32BitImm(GPRReg, APImm, B))
332         return false;
333 
334       MachineInstrBuilder MTC1 =
335           B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
336       if (!MTC1.constrainAllUses(TII, TRI, RBI))
337         return false;
338     }
339     if (Size == 64) {
340       unsigned GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
341       unsigned GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
342       MachineIRBuilder B(I);
343       if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
344         return false;
345       if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
346         return false;
347 
348       MachineInstrBuilder PairF64 = B.buildInstr(
349           STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
350           {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
351       if (!PairF64.constrainAllUses(TII, TRI, RBI))
352         return false;
353     }
354 
355     I.eraseFromParent();
356     return true;
357   }
358   case G_GLOBAL_VALUE: {
359     if (MF.getTarget().isPositionIndependent())
360       return false;
361 
362     const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
363     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
364     MachineInstr *LUi, *ADDiu;
365 
366     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
367               .addDef(LUiReg)
368               .addGlobalAddress(GVal);
369     LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
370 
371     ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
372                 .addDef(I.getOperand(0).getReg())
373                 .addUse(LUiReg)
374                 .addGlobalAddress(GVal);
375     ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
376 
377     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
378       return false;
379     if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
380       return false;
381 
382     I.eraseFromParent();
383     return true;
384   }
385   case G_ICMP: {
386     struct Instr {
387       unsigned Opcode, Def, LHS, RHS;
388       Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
389           : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
390 
391       bool hasImm() const {
392         if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
393           return true;
394         return false;
395       }
396     };
397 
398     SmallVector<struct Instr, 2> Instructions;
399     unsigned ICMPReg = I.getOperand(0).getReg();
400     unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
401     unsigned LHS = I.getOperand(2).getReg();
402     unsigned RHS = I.getOperand(3).getReg();
403     CmpInst::Predicate Cond =
404         static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
405 
406     switch (Cond) {
407     case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
408       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
409       Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
410       break;
411     case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
412       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
413       Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
414       break;
415     case CmpInst::ICMP_UGT: // LHS >  RHS -> RHS < LHS
416       Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
417       break;
418     case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
419       Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
420       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
421       break;
422     case CmpInst::ICMP_ULT: // LHS <  RHS -> LHS < RHS
423       Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
424       break;
425     case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
426       Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
427       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
428       break;
429     case CmpInst::ICMP_SGT: // LHS >  RHS -> RHS < LHS
430       Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
431       break;
432     case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
433       Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
434       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
435       break;
436     case CmpInst::ICMP_SLT: // LHS <  RHS -> LHS < RHS
437       Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
438       break;
439     case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
440       Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
441       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
442       break;
443     default:
444       return false;
445     }
446 
447     MachineIRBuilder B(I);
448     for (const struct Instr &Instruction : Instructions) {
449       MachineInstrBuilder MIB = B.buildInstr(
450           Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
451 
452       if (Instruction.hasImm())
453         MIB.addImm(Instruction.RHS);
454       else
455         MIB.addUse(Instruction.RHS);
456 
457       if (!MIB.constrainAllUses(TII, TRI, RBI))
458         return false;
459     }
460 
461     I.eraseFromParent();
462     return true;
463   }
464   default:
465     return false;
466   }
467 
468   I.eraseFromParent();
469   return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
470 }
471 
472 namespace llvm {
473 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
474                                                    MipsSubtarget &Subtarget,
475                                                    MipsRegisterBankInfo &RBI) {
476   return new MipsInstructionSelector(TM, Subtarget, RBI);
477 }
478 } // end namespace llvm
479