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     default:
100       return Opc;
101     }
102   else
103     switch (MemSizeInBytes) {
104     case 4:
105       return Mips::LW;
106     case 2:
107       return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LH : Mips::LHu;
108     case 1:
109       return Opc == TargetOpcode::G_SEXTLOAD ? Mips::LB : Mips::LBu;
110     default:
111       return Opc;
112     }
113 }
114 
115 bool MipsInstructionSelector::select(MachineInstr &I,
116                                      CodeGenCoverage &CoverageInfo) const {
117 
118   MachineBasicBlock &MBB = *I.getParent();
119   MachineFunction &MF = *MBB.getParent();
120   MachineRegisterInfo &MRI = MF.getRegInfo();
121 
122   if (!isPreISelGenericOpcode(I.getOpcode())) {
123     if (I.isCopy())
124       return selectCopy(I, TII, MRI, TRI, RBI);
125 
126     return true;
127   }
128 
129   if (selectImpl(I, CoverageInfo)) {
130     return true;
131   }
132 
133   MachineInstr *MI = nullptr;
134   using namespace TargetOpcode;
135 
136   switch (I.getOpcode()) {
137   case G_GEP: {
138     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
139              .add(I.getOperand(0))
140              .add(I.getOperand(1))
141              .add(I.getOperand(2));
142     break;
143   }
144   case G_FRAME_INDEX: {
145     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
146              .add(I.getOperand(0))
147              .add(I.getOperand(1))
148              .addImm(0);
149     break;
150   }
151   case G_STORE:
152   case G_LOAD:
153   case G_ZEXTLOAD:
154   case G_SEXTLOAD: {
155     const unsigned DestReg = I.getOperand(0).getReg();
156     const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
157     const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
158     const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
159 
160     if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
161       return false;
162 
163     const unsigned NewOpc =
164         selectLoadStoreOpCode(I.getOpcode(), OpMemSizeInBytes);
165     if (NewOpc == I.getOpcode())
166       return false;
167 
168     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
169              .add(I.getOperand(0))
170              .add(I.getOperand(1))
171              .addImm(0)
172              .addMemOperand(*I.memoperands_begin());
173     break;
174   }
175   case G_UDIV:
176   case G_UREM:
177   case G_SDIV:
178   case G_SREM: {
179     unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
180     bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
181     bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
182 
183     MachineInstr *PseudoDIV, *PseudoMove;
184     PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
185                         TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
186                     .addDef(HILOReg)
187                     .add(I.getOperand(1))
188                     .add(I.getOperand(2));
189     if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
190       return false;
191 
192     PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
193                          TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
194                      .addDef(I.getOperand(0).getReg())
195                      .addUse(HILOReg);
196     if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
197       return false;
198 
199     I.eraseFromParent();
200     return true;
201   }
202   case G_SELECT: {
203     // Handle operands with pointer type.
204     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
205              .add(I.getOperand(0))
206              .add(I.getOperand(2))
207              .add(I.getOperand(1))
208              .add(I.getOperand(3));
209     break;
210   }
211   case G_CONSTANT: {
212     int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue();
213     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
214     MachineInstr *LUi, *ORi;
215 
216     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
217               .addDef(LUiReg)
218               .addImm(Imm >> 16);
219 
220     ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi))
221               .addDef(I.getOperand(0).getReg())
222               .addUse(LUiReg)
223               .addImm(Imm & 0xFFFF);
224 
225     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
226       return false;
227     if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
228       return false;
229 
230     I.eraseFromParent();
231     return true;
232   }
233   case G_GLOBAL_VALUE: {
234     if (MF.getTarget().isPositionIndependent())
235       return false;
236 
237     const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
238     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
239     MachineInstr *LUi, *ADDiu;
240 
241     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
242               .addDef(LUiReg)
243               .addGlobalAddress(GVal);
244     LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
245 
246     ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
247                 .addDef(I.getOperand(0).getReg())
248                 .addUse(LUiReg)
249                 .addGlobalAddress(GVal);
250     ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
251 
252     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
253       return false;
254     if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
255       return false;
256 
257     I.eraseFromParent();
258     return true;
259   }
260   case G_ICMP: {
261     struct Instr {
262       unsigned Opcode, Def, LHS, RHS;
263       Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
264           : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
265 
266       bool hasImm() const {
267         if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
268           return true;
269         return false;
270       }
271     };
272 
273     SmallVector<struct Instr, 2> Instructions;
274     unsigned ICMPReg = I.getOperand(0).getReg();
275     unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
276     unsigned LHS = I.getOperand(2).getReg();
277     unsigned RHS = I.getOperand(3).getReg();
278     CmpInst::Predicate Cond =
279         static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
280 
281     switch (Cond) {
282     case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
283       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
284       Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
285       break;
286     case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
287       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
288       Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
289       break;
290     case CmpInst::ICMP_UGT: // LHS >  RHS -> RHS < LHS
291       Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
292       break;
293     case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
294       Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
295       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
296       break;
297     case CmpInst::ICMP_ULT: // LHS <  RHS -> LHS < RHS
298       Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
299       break;
300     case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
301       Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
302       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
303       break;
304     case CmpInst::ICMP_SGT: // LHS >  RHS -> RHS < LHS
305       Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
306       break;
307     case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
308       Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
309       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
310       break;
311     case CmpInst::ICMP_SLT: // LHS <  RHS -> LHS < RHS
312       Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
313       break;
314     case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
315       Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
316       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
317       break;
318     default:
319       return false;
320     }
321 
322     MachineIRBuilder B(I);
323     for (const struct Instr &Instruction : Instructions) {
324       MachineInstrBuilder MIB = B.buildInstr(
325           Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
326 
327       if (Instruction.hasImm())
328         MIB.addImm(Instruction.RHS);
329       else
330         MIB.addUse(Instruction.RHS);
331 
332       if (!MIB.constrainAllUses(TII, TRI, RBI))
333         return false;
334     }
335 
336     I.eraseFromParent();
337     return true;
338   }
339   default:
340     return false;
341   }
342 
343   I.eraseFromParent();
344   return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
345 }
346 
347 namespace llvm {
348 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
349                                                    MipsSubtarget &Subtarget,
350                                                    MipsRegisterBankInfo &RBI) {
351   return new MipsInstructionSelector(TM, Subtarget, RBI);
352 }
353 } // end namespace llvm
354