]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / Mips / MipsInstructionSelector.cpp
1 //===- MipsInstructionSelector.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 /// This file implements the targeting of the InstructionSelector class for
11 /// Mips.
12 /// \todo This should be generated by TableGen.
13 //===----------------------------------------------------------------------===//
14
15 #include "MipsRegisterBankInfo.h"
16 #include "MipsTargetMachine.h"
17 #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
18 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
19
20 #define DEBUG_TYPE "mips-isel"
21
22 using namespace llvm;
23
24 namespace {
25
26 #define GET_GLOBALISEL_PREDICATE_BITSET
27 #include "MipsGenGlobalISel.inc"
28 #undef GET_GLOBALISEL_PREDICATE_BITSET
29
30 class MipsInstructionSelector : public InstructionSelector {
31 public:
32   MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
33                           const MipsRegisterBankInfo &RBI);
34
35   bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
36   static const char *getName() { return DEBUG_TYPE; }
37
38 private:
39   bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
40
41   const MipsTargetMachine &TM;
42   const MipsSubtarget &STI;
43   const MipsInstrInfo &TII;
44   const MipsRegisterInfo &TRI;
45   const MipsRegisterBankInfo &RBI;
46
47 #define GET_GLOBALISEL_PREDICATES_DECL
48 #include "MipsGenGlobalISel.inc"
49 #undef GET_GLOBALISEL_PREDICATES_DECL
50
51 #define GET_GLOBALISEL_TEMPORARIES_DECL
52 #include "MipsGenGlobalISel.inc"
53 #undef GET_GLOBALISEL_TEMPORARIES_DECL
54 };
55
56 } // end anonymous namespace
57
58 #define GET_GLOBALISEL_IMPL
59 #include "MipsGenGlobalISel.inc"
60 #undef GET_GLOBALISEL_IMPL
61
62 MipsInstructionSelector::MipsInstructionSelector(
63     const MipsTargetMachine &TM, const MipsSubtarget &STI,
64     const MipsRegisterBankInfo &RBI)
65     : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
66       TRI(*STI.getRegisterInfo()), RBI(RBI),
67
68 #define GET_GLOBALISEL_PREDICATES_INIT
69 #include "MipsGenGlobalISel.inc"
70 #undef GET_GLOBALISEL_PREDICATES_INIT
71 #define GET_GLOBALISEL_TEMPORARIES_INIT
72 #include "MipsGenGlobalISel.inc"
73 #undef GET_GLOBALISEL_TEMPORARIES_INIT
74 {
75 }
76
77 static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
78                        MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
79                        const RegisterBankInfo &RBI) {
80   unsigned DstReg = I.getOperand(0).getReg();
81   if (TargetRegisterInfo::isPhysicalRegister(DstReg))
82     return true;
83
84   const TargetRegisterClass *RC = &Mips::GPR32RegClass;
85
86   if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
87     LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
88                       << " operand\n");
89     return false;
90   }
91   return true;
92 }
93
94 bool MipsInstructionSelector::select(MachineInstr &I,
95                                      CodeGenCoverage &CoverageInfo) const {
96
97   MachineBasicBlock &MBB = *I.getParent();
98   MachineFunction &MF = *MBB.getParent();
99   MachineRegisterInfo &MRI = MF.getRegInfo();
100
101   if (!isPreISelGenericOpcode(I.getOpcode())) {
102     if (I.isCopy())
103       return selectCopy(I, TII, MRI, TRI, RBI);
104
105     return true;
106   }
107
108   if (selectImpl(I, CoverageInfo)) {
109     return true;
110   }
111
112   MachineInstr *MI = nullptr;
113   using namespace TargetOpcode;
114
115   switch (I.getOpcode()) {
116   case G_GEP: {
117     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
118              .add(I.getOperand(0))
119              .add(I.getOperand(1))
120              .add(I.getOperand(2));
121     break;
122   }
123   case G_FRAME_INDEX: {
124     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
125              .add(I.getOperand(0))
126              .add(I.getOperand(1))
127              .addImm(0);
128     break;
129   }
130   case G_STORE:
131   case G_LOAD: {
132     const unsigned DestReg = I.getOperand(0).getReg();
133     const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
134     const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
135
136     if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
137       return false;
138
139     const unsigned NewOpc = I.getOpcode() == G_STORE ? Mips::SW : Mips::LW;
140
141     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
142              .add(I.getOperand(0))
143              .add(I.getOperand(1))
144              .addImm(0)
145              .addMemOperand(*I.memoperands_begin());
146     break;
147   }
148   case G_UDIV:
149   case G_UREM:
150   case G_SDIV:
151   case G_SREM: {
152     unsigned HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
153     bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
154     bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
155
156     MachineInstr *PseudoDIV, *PseudoMove;
157     PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
158                         TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
159                     .addDef(HILOReg)
160                     .add(I.getOperand(1))
161                     .add(I.getOperand(2));
162     if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
163       return false;
164
165     PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
166                          TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
167                      .addDef(I.getOperand(0).getReg())
168                      .addUse(HILOReg);
169     if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
170       return false;
171
172     I.eraseFromParent();
173     return true;
174   }
175   case G_SELECT: {
176     // Handle operands with pointer type.
177     MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
178              .add(I.getOperand(0))
179              .add(I.getOperand(2))
180              .add(I.getOperand(1))
181              .add(I.getOperand(3));
182     break;
183   }
184   case G_CONSTANT: {
185     int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue();
186     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
187     MachineInstr *LUi, *ORi;
188
189     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
190               .addDef(LUiReg)
191               .addImm(Imm >> 16);
192
193     ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi))
194               .addDef(I.getOperand(0).getReg())
195               .addUse(LUiReg)
196               .addImm(Imm & 0xFFFF);
197
198     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
199       return false;
200     if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
201       return false;
202
203     I.eraseFromParent();
204     return true;
205   }
206   case G_GLOBAL_VALUE: {
207     if (MF.getTarget().isPositionIndependent())
208       return false;
209
210     const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
211     unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
212     MachineInstr *LUi, *ADDiu;
213
214     LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
215               .addDef(LUiReg)
216               .addGlobalAddress(GVal);
217     LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
218
219     ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
220                 .addDef(I.getOperand(0).getReg())
221                 .addUse(LUiReg)
222                 .addGlobalAddress(GVal);
223     ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
224
225     if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
226       return false;
227     if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
228       return false;
229
230     I.eraseFromParent();
231     return true;
232   }
233   case G_ICMP: {
234     struct Instr {
235       unsigned Opcode, Def, LHS, RHS;
236       Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
237           : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
238
239       bool hasImm() const {
240         if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
241           return true;
242         return false;
243       }
244     };
245
246     SmallVector<struct Instr, 2> Instructions;
247     unsigned ICMPReg = I.getOperand(0).getReg();
248     unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
249     unsigned LHS = I.getOperand(2).getReg();
250     unsigned RHS = I.getOperand(3).getReg();
251     CmpInst::Predicate Cond =
252         static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
253
254     switch (Cond) {
255     case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
256       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
257       Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
258       break;
259     case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
260       Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
261       Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
262       break;
263     case CmpInst::ICMP_UGT: // LHS >  RHS -> RHS < LHS
264       Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
265       break;
266     case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
267       Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
268       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
269       break;
270     case CmpInst::ICMP_ULT: // LHS <  RHS -> LHS < RHS
271       Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
272       break;
273     case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
274       Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
275       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
276       break;
277     case CmpInst::ICMP_SGT: // LHS >  RHS -> RHS < LHS
278       Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
279       break;
280     case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
281       Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
282       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
283       break;
284     case CmpInst::ICMP_SLT: // LHS <  RHS -> LHS < RHS
285       Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
286       break;
287     case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
288       Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
289       Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
290       break;
291     default:
292       return false;
293     }
294
295     MachineIRBuilder B(I);
296     for (const struct Instr &Instruction : Instructions) {
297       MachineInstrBuilder MIB = B.buildInstr(
298           Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
299
300       if (Instruction.hasImm())
301         MIB.addImm(Instruction.RHS);
302       else
303         MIB.addUse(Instruction.RHS);
304
305       if (!MIB.constrainAllUses(TII, TRI, RBI))
306         return false;
307     }
308
309     I.eraseFromParent();
310     return true;
311   }
312   default:
313     return false;
314   }
315
316   I.eraseFromParent();
317   return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
318 }
319
320 namespace llvm {
321 InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
322                                                    MipsSubtarget &Subtarget,
323                                                    MipsRegisterBankInfo &RBI) {
324   return new MipsInstructionSelector(TM, Subtarget, RBI);
325 }
326 } // end namespace llvm