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 
40   const MipsTargetMachine &TM;
41   const MipsSubtarget &STI;
42   const MipsInstrInfo &TII;
43   const MipsRegisterInfo &TRI;
44   const MipsRegisterBankInfo &RBI;
45 
46 #define GET_GLOBALISEL_PREDICATES_DECL
47 #include "MipsGenGlobalISel.inc"
48 #undef GET_GLOBALISEL_PREDICATES_DECL
49 
50 #define GET_GLOBALISEL_TEMPORARIES_DECL
51 #include "MipsGenGlobalISel.inc"
52 #undef GET_GLOBALISEL_TEMPORARIES_DECL
53 };
54 
55 } // end anonymous namespace
56 
57 #define GET_GLOBALISEL_IMPL
58 #include "MipsGenGlobalISel.inc"
59 #undef GET_GLOBALISEL_IMPL
60 
61 MipsInstructionSelector::MipsInstructionSelector(
62     const MipsTargetMachine &TM, const MipsSubtarget &STI,
63     const MipsRegisterBankInfo &RBI)
64     : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
65       TRI(*STI.getRegisterInfo()), RBI(RBI),
66 
67 #define GET_GLOBALISEL_PREDICATES_INIT
68 #include "MipsGenGlobalISel.inc"
69 #undef GET_GLOBALISEL_PREDICATES_INIT
70 #define GET_GLOBALISEL_TEMPORARIES_INIT
71 #include "MipsGenGlobalISel.inc"
72 #undef GET_GLOBALISEL_TEMPORARIES_INIT
73 {
74 }
75 
76 static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
77                        MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
78                        const RegisterBankInfo &RBI) {
79   unsigned DstReg = I.getOperand(0).getReg();
80   if (TargetRegisterInfo::isPhysicalRegister(DstReg))
81     return true;
82 
83   const TargetRegisterClass *RC = &Mips::GPR32RegClass;
84 
85   if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
86     LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
87                       << " operand\n");
88     return false;
89   }
90   return true;
91 }
92 
93 /// Returning Opc indicates that we failed to select MIPS instruction opcode.
94 static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned MemSizeInBytes) {
95   if (Opc == TargetOpcode::G_STORE)
96     switch (MemSizeInBytes) {
97     case 4:
98       return Mips::SW;
99     case 2:
100       return Mips::SH;
101     case 1:
102       return Mips::SB;
103     default:
104       return Opc;
105     }
106   else
107     // Unspecified extending load is selected into zeroExtending load.
108     switch (MemSizeInBytes) {
109     case 4:
110       return Mips::LW;
111     case 2:
112       return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
113     case 1:
114       return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
115     default:
116       return Opc;
117     }
118 }
119 
120 bool MipsInstructionSelector::select(MachineInstr &I,
121                                      CodeGenCoverage &CoverageInfo) const {
122 
123   MachineBasicBlock &MBB = *I.getParent();
124   MachineFunction &MF = *MBB.getParent();
125   MachineRegisterInfo &MRI = MF.getRegInfo();
126 
127   if (!isPreISelGenericOpcode(I.getOpcode())) {
128     if (I.isCopy())
129       return selectCopy(I, TII, MRI, TRI, RBI);
130 
131     return true;
132   }
133 
134   if (I.getOpcode() == Mips::G_MUL) {
135     MachineInstr *Mul = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MUL))
136                             .add(I.getOperand(0))
137                             .add(I.getOperand(1))
138                             .add(I.getOperand(2));
139     if (!constrainSelectedInstRegOperands(*Mul, TII, TRI, RBI))
140       return false;
141     Mul->getOperand(3).setIsDead(true);
142     Mul->getOperand(4).setIsDead(true);
143 
144     I.eraseFromParent();
145     return true;
146   }
147 
148   if (selectImpl(I, CoverageInfo))
149     return true;
150 
151   MachineInstr *MI = nullptr;
152   using namespace TargetOpcode;
153 
154   switch (I.getOpcode()) {
155   case G_UMULH: {
156     unsigned PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
157     MachineInstr *PseudoMULTu, *PseudoMove;
158 
159     PseudoMULTu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMULTu))
160                       .addDef(PseudoMULTuReg)
161                       .add(I.getOperand(1))
162                       .add(I.getOperand(2));
163     if (!constrainSelectedInstRegOperands(*PseudoMULTu, TII, TRI, RBI))
164       return false;
165 
166     PseudoMove = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::PseudoMFHI))
167                      .addDef(I.getOperand(0).getReg())
168                      .addUse(PseudoMULTuReg);
169     if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
170       return false;
171 
172     I.eraseFromParent();
173     return true;
174   }
175   case G_GEP: {
176     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
177              .add(I.getOperand(0))
178              .add(I.getOperand(1))
179              .add(I.getOperand(2));
180     break;
181   }
182   case G_FRAME_INDEX: {
183     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
184              .add(I.getOperand(0))
185              .add(I.getOperand(1))
186              .addImm(0);
187     break;
188   }
189   case G_BRCOND: {
190     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
191              .add(I.getOperand(0))
192              .addUse(Mips::ZERO)
193              .add(I.getOperand(1));
194     break;
195   }
196   case G_PHI: {
197     const unsigned DestReg = I.getOperand(0).getReg();
198     const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
199     const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
200 
201     if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
202       return false;
203 
204     const TargetRegisterClass *DefRC = &Mips::GPR32RegClass;
205     I.setDesc(TII.get(TargetOpcode::PHI));
206     return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
207   }
208   case G_STORE:
209   case G_LOAD:
210   case G_ZEXTLOAD:
211   case G_SEXTLOAD: {
212     const unsigned DestReg = I.getOperand(0).getReg();
213     const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
214     const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
215     const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
216 
217     if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
218       return false;
219 
220     const unsigned NewOpc =
221         selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes);
222     if (NewOpc == I.getOpcode())
223       return false;
224 
225     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
226              .add(I.getOperand(0))
227              .add(I.getOperand(1))
228              .addImm(0)
229              .addMemOperand(*I.memoperands_begin());
230     break;
231   }
232   case G_UDIV:
233   case G_UREM:
234   case G_SDIV:
235   case G_SREM: {
236     unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
237     bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
238     bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
239 
240     MachineInstr *PseudoDIV, *PseudoMove;
241     PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
242                         TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
243                     .addDef(HILOReg)
244                     .add(I.getOperand(1))
245                     .add(I.getOperand(2));
246     if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
247       return false;
248 
249     PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
250                          TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
251                      .addDef(I.getOperand(0).getReg())
252                      .addUse(HILOReg);
253     if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
254       return false;
255 
256     I.eraseFromParent();
257     return true;
258   }
259   case G_SELECT: {
260     // Handle operands with pointer type.
261     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
262              .add(I.getOperand(0))
263              .add(I.getOperand(2))
264              .add(I.getOperand(1))
265              .add(I.getOperand(3));
266     break;
267   }
268   case G_CONSTANT: {
269     int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue();
270     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
271     MachineInstr *LUi, *ORi;
272 
273     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
274               .addDef(LUiReg)
275               .addImm(Imm >> 16);
276 
277     ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi))
278               .addDef(I.getOperand(0).getReg())
279               .addUse(LUiReg)
280               .addImm(Imm & 0xFFFF);
281 
282     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
283       return false;
284     if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
285       return false;
286 
287     I.eraseFromParent();
288     return true;
289   }
290   case G_GLOBAL_VALUE: {
291     if (MF.getTarget().isPositionIndependent())
292       return false;
293 
294     const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
295     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
296     MachineInstr *LUi, *ADDiu;
297 
298     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
299               .addDef(LUiReg)
300               .addGlobalAddress(GVal);
301     LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
302 
303     ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
304                 .addDef(I.getOperand(0).getReg())
305                 .addUse(LUiReg)
306                 .addGlobalAddress(GVal);
307     ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
308 
309     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
310       return false;
311     if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
312       return false;
313 
314     I.eraseFromParent();
315     return true;
316   }
317   case G_ICMP: {
318     struct Instr {
319       unsigned Opcode, Def, LHS, RHS;
320       Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
321           : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
322 
323       bool hasImm() const {
324         if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
325           return true;
326         return false;
327       }
328     };
329 
330     SmallVector<struct Instr, 2> Instructions;
331     unsigned ICMPReg = I.getOperand(0).getReg();
332     unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
333     unsigned LHS = I.getOperand(2).getReg();
334     unsigned RHS = I.getOperand(3).getReg();
335     CmpInst::Predicate Cond =
336         static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
337 
338     switch (Cond) {
339     case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
340       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
341       Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
342       break;
343     case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
344       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
345       Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
346       break;
347     case CmpInst::ICMP_UGT: // LHS >  RHS -> RHS < LHS
348       Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
349       break;
350     case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
351       Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
352       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
353       break;
354     case CmpInst::ICMP_ULT: // LHS <  RHS -> LHS < RHS
355       Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
356       break;
357     case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
358       Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
359       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
360       break;
361     case CmpInst::ICMP_SGT: // LHS >  RHS -> RHS < LHS
362       Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
363       break;
364     case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
365       Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
366       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
367       break;
368     case CmpInst::ICMP_SLT: // LHS <  RHS -> LHS < RHS
369       Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
370       break;
371     case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
372       Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
373       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
374       break;
375     default:
376       return false;
377     }
378 
379     MachineIRBuilder B(I);
380     for (const struct Instr &Instruction : Instructions) {
381       MachineInstrBuilder MIB = B.buildInstr(
382           Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
383 
384       if (Instruction.hasImm())
385         MIB.addImm(Instruction.RHS);
386       else
387         MIB.addUse(Instruction.RHS);
388 
389       if (!MIB.constrainAllUses(TII, TRI, RBI))
390         return false;
391     }
392 
393     I.eraseFromParent();
394     return true;
395   }
396   default:
397     return false;
398   }
399 
400   I.eraseFromParent();
401   return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
402 }
403 
404 namespace llvm {
405 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
406                                                    MipsSubtarget &Subtarget,
407                                                    MipsRegisterBankInfo &RBI) {
408   return new MipsInstructionSelector(TM, Subtarget, RBI);
409 }
410 } // end namespace llvm
411