blob: 45a47ad3c087ca79ca7023b10ccad40903af31c3 [file] [log] [blame]
Petar Jovanovicfac93e22018-02-23 11:06:40 +00001//===- MipsInstructionSelector.cpp ------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Petar Jovanovicfac93e22018-02-23 11:06:40 +00006//
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
Petar Avramovic22e99c42019-06-05 14:03:13 +000014#include "MCTargetDesc/MipsInstPrinter.h"
Petar Avramovicefcd3c02019-05-31 08:27:06 +000015#include "MipsMachineFunction.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000016#include "MipsRegisterBankInfo.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000017#include "MipsTargetMachine.h"
Petar Jovanovic366857a2018-04-11 15:12:32 +000018#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +000019#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
Petar Jovanovicfac93e22018-02-23 11:06:40 +000020
Petar Jovanovic366857a2018-04-11 15:12:32 +000021#define DEBUG_TYPE "mips-isel"
22
Petar Jovanovicfac93e22018-02-23 11:06:40 +000023using namespace llvm;
24
25namespace {
26
Petar Jovanovic366857a2018-04-11 15:12:32 +000027#define GET_GLOBALISEL_PREDICATE_BITSET
28#include "MipsGenGlobalISel.inc"
29#undef GET_GLOBALISEL_PREDICATE_BITSET
30
Petar Jovanovicfac93e22018-02-23 11:06:40 +000031class MipsInstructionSelector : public InstructionSelector {
32public:
33 MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
34 const MipsRegisterBankInfo &RBI);
35
36 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
Petar Jovanovic366857a2018-04-11 15:12:32 +000037 static const char *getName() { return DEBUG_TYPE; }
Petar Jovanovicfac93e22018-02-23 11:06:40 +000038
39private:
Petar Jovanovic366857a2018-04-11 15:12:32 +000040 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +000041 bool materialize32BitImm(Register DestReg, APInt Imm,
Petar Avramovic3e0da142019-03-15 07:07:50 +000042 MachineIRBuilder &B) const;
Petar Avramovica034a642019-03-25 11:38:06 +000043 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
Petar Avramovic7d0778e2019-07-10 13:18:13 +000044 const TargetRegisterClass *
45 getRegClassForTypeOnBank(unsigned OpSize, const RegisterBank &RB,
46 const RegisterBankInfo &RBI) const;
Petar Jovanovic366857a2018-04-11 15:12:32 +000047
48 const MipsTargetMachine &TM;
49 const MipsSubtarget &STI;
Petar Jovanovicfac93e22018-02-23 11:06:40 +000050 const MipsInstrInfo &TII;
51 const MipsRegisterInfo &TRI;
Petar Jovanovic366857a2018-04-11 15:12:32 +000052 const MipsRegisterBankInfo &RBI;
53
54#define GET_GLOBALISEL_PREDICATES_DECL
55#include "MipsGenGlobalISel.inc"
56#undef GET_GLOBALISEL_PREDICATES_DECL
57
58#define GET_GLOBALISEL_TEMPORARIES_DECL
59#include "MipsGenGlobalISel.inc"
60#undef GET_GLOBALISEL_TEMPORARIES_DECL
Petar Jovanovicfac93e22018-02-23 11:06:40 +000061};
62
63} // end anonymous namespace
64
Petar Jovanovic366857a2018-04-11 15:12:32 +000065#define GET_GLOBALISEL_IMPL
66#include "MipsGenGlobalISel.inc"
67#undef GET_GLOBALISEL_IMPL
68
Petar Jovanovicfac93e22018-02-23 11:06:40 +000069MipsInstructionSelector::MipsInstructionSelector(
70 const MipsTargetMachine &TM, const MipsSubtarget &STI,
71 const MipsRegisterBankInfo &RBI)
Petar Jovanovic366857a2018-04-11 15:12:32 +000072 : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
73 TRI(*STI.getRegisterInfo()), RBI(RBI),
74
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
81{
82}
83
Petar Avramovica034a642019-03-25 11:38:06 +000084bool MipsInstructionSelector::selectCopy(MachineInstr &I,
85 MachineRegisterInfo &MRI) const {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +000086 Register DstReg = I.getOperand(0).getReg();
Petar Jovanovic366857a2018-04-11 15:12:32 +000087 if (TargetRegisterInfo::isPhysicalRegister(DstReg))
88 return true;
89
Petar Avramovica034a642019-03-25 11:38:06 +000090 const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI);
91 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
Petar Jovanovic366857a2018-04-11 15:12:32 +000092
Petar Avramovica034a642019-03-25 11:38:06 +000093 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");
101 }
Petar Jovanovic366857a2018-04-11 15:12:32 +0000102 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000103 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
104 << " operand\n");
Petar Jovanovic366857a2018-04-11 15:12:32 +0000105 return false;
106 }
107 return true;
108}
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000109
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000110const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank(
111 unsigned OpSize, const RegisterBank &RB,
112 const RegisterBankInfo &RBI) const {
113 if (RB.getID() == Mips::GPRBRegBankID)
114 return &Mips::GPR32RegClass;
115
116 if (RB.getID() == Mips::FPRBRegBankID)
117 return OpSize == 32
118 ? &Mips::FGR32RegClass
119 : STI.hasMips32r6() || STI.isFP64bit() ? &Mips::FGR64RegClass
120 : &Mips::AFGR64RegClass;
121
122 llvm_unreachable("getRegClassForTypeOnBank can't find register class.");
123 return nullptr;
124}
125
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000126bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm,
Petar Avramovic3e0da142019-03-15 07:07:50 +0000127 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()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000131 MachineInstr *Inst = B.buildInstr(Mips::ORi, {DestReg}, {Register(Mips::ZERO)})
Petar Avramovic3e0da142019-03-15 07:07:50 +0000132 .addImm(Imm.getLoBits(16).getLimitedValue());
133 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
134 }
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);
140 }
141 // ADDiu sign extends immediate. Used for values with 1s in high 17 bits.
142 if (Imm.isSignedIntN(16)) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000143 MachineInstr *Inst = B.buildInstr(Mips::ADDiu, {DestReg}, {Register(Mips::ZERO)})
Petar Avramovic3e0da142019-03-15 07:07:50 +0000144 .addImm(Imm.getLoBits(16).getLimitedValue());
145 return constrainSelectedInstRegOperands(*Inst, TII, TRI, RBI);
146 }
147 // Values that cannot be materialized with single immediate instruction.
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000148 Register LUiReg = B.getMRI()->createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic3e0da142019-03-15 07:07:50 +0000149 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;
158}
159
Petar Avramovic79df8592019-01-24 10:27:21 +0000160/// Returning Opc indicates that we failed to select MIPS instruction opcode.
Petar Avramovic7b314912019-07-10 12:55:21 +0000161static 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;
175 }
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;
187 }
188 }
189
190 if (RegBank == Mips::FPRBRegBankID) {
Petar Avramovic79df8592019-01-24 10:27:21 +0000191 switch (MemSizeInBytes) {
192 case 4:
Petar Avramovic7b314912019-07-10 12:55:21 +0000193 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;
Petar Avramovic79df8592019-01-24 10:27:21 +0000199 default:
200 return Opc;
201 }
Petar Avramovic7b314912019-07-10 12:55:21 +0000202 }
203 return Opc;
Petar Avramovic79df8592019-01-24 10:27:21 +0000204}
205
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000206bool MipsInstructionSelector::select(MachineInstr &I,
207 CodeGenCoverage &CoverageInfo) const {
208
Petar Jovanovic366857a2018-04-11 15:12:32 +0000209 MachineBasicBlock &MBB = *I.getParent();
210 MachineFunction &MF = *MBB.getParent();
211 MachineRegisterInfo &MRI = MF.getRegInfo();
212
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000213 if (!isPreISelGenericOpcode(I.getOpcode())) {
Petar Jovanovic366857a2018-04-11 15:12:32 +0000214 if (I.isCopy())
Petar Avramovica034a642019-03-25 11:38:06 +0000215 return selectCopy(I, MRI);
Petar Jovanovic366857a2018-04-11 15:12:32 +0000216
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000217 return true;
218 }
219
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000220 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);
229
230 I.eraseFromParent();
Petar Jovanovic366857a2018-04-11 15:12:32 +0000231 return true;
232 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000233
Petar Avramovic3d3120d2019-03-07 13:28:29 +0000234 if (selectImpl(I, CoverageInfo))
235 return true;
236
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000237 MachineInstr *MI = nullptr;
238 using namespace TargetOpcode;
239
240 switch (I.getOpcode()) {
Petar Avramovica48285a2019-03-01 07:25:44 +0000241 case G_UMULH: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000242 Register PseudoMULTuReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovica48285a2019-03-01 07:25:44 +0000243 MachineInstr *PseudoMULTu, *PseudoMove;
244
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;
251
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;
257
258 I.eraseFromParent();
259 return true;
260 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000261 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;
267 }
268 case G_FRAME_INDEX: {
269 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
270 .add(I.getOperand(0))
271 .add(I.getOperand(1))
272 .addImm(0);
273 break;
274 }
Petar Avramovic5d9b8ee2019-02-14 11:39:53 +0000275 case G_BRCOND: {
276 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::BNE))
277 .add(I.getOperand(0))
278 .addUse(Mips::ZERO)
279 .add(I.getOperand(1));
280 break;
281 }
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000282 case G_PHI: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000283 const Register DestReg = I.getOperand(0).getReg();
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000284 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
285
Petar Avramovic7d0778e2019-07-10 13:18:13 +0000286 const TargetRegisterClass *DefRC = nullptr;
287 if (TargetRegisterInfo::isPhysicalRegister(DestReg))
288 DefRC = TRI.getRegClass(DestReg);
289 else
290 DefRC = getRegClassForTypeOnBank(OpSize,
291 *RBI.getRegBank(DestReg, MRI, TRI), RBI);
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000292
Petar Avramovic14c7ecf2019-02-14 12:36:19 +0000293 I.setDesc(TII.get(TargetOpcode::PHI));
294 return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
295 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000296 case G_STORE:
Petar Avramovic79df8592019-01-24 10:27:21 +0000297 case G_LOAD:
298 case G_ZEXTLOAD:
299 case G_SEXTLOAD: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000300 const Register DestReg = I.getOperand(0).getReg();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000301 const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
302 const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
Petar Avramovic79df8592019-01-24 10:27:21 +0000303 const unsigned OpMemSizeInBytes = (*I.memoperands_begin())->getSize();
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000304
Petar Avramovic7b314912019-07-10 12:55:21 +0000305 if (DestRegBank == Mips::GPRBRegBankID && OpSize != 32)
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000306 return false;
307
Petar Avramovic7b314912019-07-10 12:55:21 +0000308 if (DestRegBank == Mips::FPRBRegBankID && OpSize != 32 && OpSize != 64)
309 return false;
310
311 const unsigned NewOpc = selectLoadStoreOpCode(
312 I.getOpcode(), OpMemSizeInBytes, DestRegBank, STI.isFP64bit());
Petar Avramovic79df8592019-01-24 10:27:21 +0000313 if (NewOpc == I.getOpcode())
314 return false;
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000315
316 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
317 .add(I.getOperand(0))
318 .add(I.getOperand(1))
319 .addImm(0)
320 .addMemOperand(*I.memoperands_begin());
321 break;
322 }
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000323 case G_UDIV:
324 case G_UREM:
325 case G_SDIV:
326 case G_SREM: {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000327 Register HILOReg = MRI.createVirtualRegister(&Mips::ACC64RegClass);
Petar Avramovic0a5e4eb2018-12-18 15:59:51 +0000328 bool IsSigned = I.getOpcode() == G_SREM || I.getOpcode() == G_SDIV;
329 bool IsDiv = I.getOpcode() == G_UDIV || I.getOpcode() == G_SDIV;
330
331 MachineInstr *PseudoDIV, *PseudoMove;
332 PseudoDIV = BuildMI(MBB, I, I.getDebugLoc(),
333 TII.get(IsSigned ? Mips::PseudoSDIV : Mips::PseudoUDIV))
334 .addDef(HILOReg)
335 .add(I.getOperand(1))
336 .add(I.getOperand(2));
337 if (!constrainSelectedInstRegOperands(*PseudoDIV, TII, TRI, RBI))
338 return false;
339
340 PseudoMove = BuildMI(MBB, I, I.getDebugLoc(),
341 TII.get(IsDiv ? Mips::PseudoMFLO : Mips::PseudoMFHI))
342 .addDef(I.getOperand(0).getReg())
343 .addUse(HILOReg);
344 if (!constrainSelectedInstRegOperands(*PseudoMove, TII, TRI, RBI))
345 return false;
346
347 I.eraseFromParent();
348 return true;
349 }
Petar Avramovic09dff332018-12-25 14:42:30 +0000350 case G_SELECT: {
351 // Handle operands with pointer type.
352 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MOVN_I_I))
353 .add(I.getOperand(0))
354 .add(I.getOperand(2))
355 .add(I.getOperand(1))
356 .add(I.getOperand(3));
357 break;
358 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000359 case G_CONSTANT: {
Petar Avramovic3e0da142019-03-15 07:07:50 +0000360 MachineIRBuilder B(I);
361 if (!materialize32BitImm(I.getOperand(0).getReg(),
362 I.getOperand(1).getCImm()->getValue(), B))
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000363 return false;
364
365 I.eraseFromParent();
366 return true;
367 }
Petar Avramovic1af05df2019-03-28 16:58:12 +0000368 case G_FCONSTANT: {
369 const APFloat &FPimm = I.getOperand(1).getFPImm()->getValueAPF();
370 APInt APImm = FPimm.bitcastToAPInt();
371 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
372
373 if (Size == 32) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000374 Register GPRReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000375 MachineIRBuilder B(I);
376 if (!materialize32BitImm(GPRReg, APImm, B))
377 return false;
378
379 MachineInstrBuilder MTC1 =
380 B.buildInstr(Mips::MTC1, {I.getOperand(0).getReg()}, {GPRReg});
381 if (!MTC1.constrainAllUses(TII, TRI, RBI))
382 return false;
383 }
384 if (Size == 64) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000385 Register GPRRegHigh = MRI.createVirtualRegister(&Mips::GPR32RegClass);
386 Register GPRRegLow = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovic1af05df2019-03-28 16:58:12 +0000387 MachineIRBuilder B(I);
388 if (!materialize32BitImm(GPRRegHigh, APImm.getHiBits(32).trunc(32), B))
389 return false;
390 if (!materialize32BitImm(GPRRegLow, APImm.getLoBits(32).trunc(32), B))
391 return false;
392
393 MachineInstrBuilder PairF64 = B.buildInstr(
394 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64,
395 {I.getOperand(0).getReg()}, {GPRRegLow, GPRRegHigh});
396 if (!PairF64.constrainAllUses(TII, TRI, RBI))
397 return false;
398 }
399
400 I.eraseFromParent();
401 return true;
402 }
Petar Avramovic0a1fd352019-06-06 09:22:37 +0000403 case G_FABS: {
404 unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
405 unsigned FABSOpcode =
406 Size == 32 ? Mips::FABS_S
407 : STI.isFP64bit() ? Mips::FABS_D64 : Mips::FABS_D32;
408 MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FABSOpcode))
409 .add(I.getOperand(0))
410 .add(I.getOperand(1));
411 break;
412 }
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000413 case G_FPTOSI: {
414 unsigned FromSize = MRI.getType(I.getOperand(1).getReg()).getSizeInBits();
415 unsigned ToSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits();
Fangrui Songddd056c2019-06-21 01:51:50 +0000416 (void)ToSize;
Petar Avramovic4b4dae12019-06-20 08:52:53 +0000417 assert((ToSize == 32) && "Unsupported integer size for G_FPTOSI");
418 assert((FromSize == 32 || FromSize == 64) &&
419 "Unsupported floating point size for G_FPTOSI");
420
421 unsigned Opcode;
422 if (FromSize == 32)
423 Opcode = Mips::TRUNC_W_S;
424 else
425 Opcode = STI.isFP64bit() ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32;
426 unsigned ResultInFPR = MRI.createVirtualRegister(&Mips::FGR32RegClass);
427 MachineInstr *Trunc = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode))
428 .addDef(ResultInFPR)
429 .addUse(I.getOperand(1).getReg());
430 if (!constrainSelectedInstRegOperands(*Trunc, TII, TRI, RBI))
431 return false;
432
433 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::MFC1))
434 .addDef(I.getOperand(0).getReg())
435 .addUse(ResultInFPR);
436 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
437 return false;
438
439 I.eraseFromParent();
440 return true;
441 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000442 case G_GLOBAL_VALUE: {
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000443 const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000444 if (MF.getTarget().isPositionIndependent()) {
445 MachineInstr *LWGOT = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LW))
446 .addDef(I.getOperand(0).getReg())
447 .addReg(MF.getInfo<MipsFunctionInfo>()
448 ->getGlobalBaseRegForGlobalISel())
449 .addGlobalAddress(GVal);
450 // Global Values that don't have local linkage are handled differently
451 // when they are part of call sequence. MipsCallLowering::lowerCall
452 // creates G_GLOBAL_VALUE instruction as part of call sequence and adds
453 // MO_GOT_CALL flag when Callee doesn't have local linkage.
454 if (I.getOperand(1).getTargetFlags() == MipsII::MO_GOT_CALL)
455 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT_CALL);
456 else
457 LWGOT->getOperand(2).setTargetFlags(MipsII::MO_GOT);
458 LWGOT->addMemOperand(
459 MF, MF.getMachineMemOperand(MachinePointerInfo::getGOT(MF),
460 MachineMemOperand::MOLoad, 4, 4));
461 if (!constrainSelectedInstRegOperands(*LWGOT, TII, TRI, RBI))
462 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000463
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000464 if (GVal->hasLocalLinkage()) {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000465 Register LWGOTDef = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000466 LWGOT->getOperand(0).setReg(LWGOTDef);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000467
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000468 MachineInstr *ADDiu =
469 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000470 .addDef(I.getOperand(0).getReg())
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000471 .addReg(LWGOTDef)
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000472 .addGlobalAddress(GVal);
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000473 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
474 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
475 return false;
476 }
477 } else {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000478 Register LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000479
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000480 MachineInstr *LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
481 .addDef(LUiReg)
482 .addGlobalAddress(GVal);
483 LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
484 if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
485 return false;
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000486
Petar Avramovicefcd3c02019-05-31 08:27:06 +0000487 MachineInstr *ADDiu =
488 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
489 .addDef(I.getOperand(0).getReg())
490 .addUse(LUiReg)
491 .addGlobalAddress(GVal);
492 ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
493 if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
494 return false;
495 }
Petar Jovanovic64c10ba2018-08-01 09:03:23 +0000496 I.eraseFromParent();
497 return true;
498 }
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000499 case G_ICMP: {
500 struct Instr {
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000501 unsigned Opcode;
502 Register Def, LHS, RHS;
503 Instr(unsigned Opcode, Register Def, Register LHS, Register RHS)
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000504 : Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000505
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000506 bool hasImm() const {
507 if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
508 return true;
509 return false;
510 }
511 };
512
513 SmallVector<struct Instr, 2> Instructions;
Matt Arsenaultfaeaedf2019-06-24 16:16:12 +0000514 Register ICMPReg = I.getOperand(0).getReg();
515 Register Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
516 Register LHS = I.getOperand(2).getReg();
517 Register RHS = I.getOperand(3).getReg();
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000518 CmpInst::Predicate Cond =
519 static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
520
521 switch (Cond) {
522 case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
523 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
524 Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
525 break;
526 case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
527 Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
528 Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
529 break;
530 case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
531 Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
532 break;
533 case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
534 Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
535 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
536 break;
537 case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
538 Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
539 break;
540 case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
541 Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
542 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
543 break;
544 case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
545 Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
546 break;
547 case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
548 Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
549 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
550 break;
551 case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
552 Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
553 break;
554 case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
555 Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
556 Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
557 break;
558 default:
559 return false;
560 }
561
562 MachineIRBuilder B(I);
563 for (const struct Instr &Instruction : Instructions) {
Aditya Nandakumarcef44a22018-12-11 00:48:50 +0000564 MachineInstrBuilder MIB = B.buildInstr(
565 Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
Petar Jovanovicce4dd0a2018-09-10 15:56:52 +0000566
567 if (Instruction.hasImm())
568 MIB.addImm(Instruction.RHS);
569 else
570 MIB.addUse(Instruction.RHS);
571
572 if (!MIB.constrainAllUses(TII, TRI, RBI))
573 return false;
574 }
575
576 I.eraseFromParent();
577 return true;
578 }
Petar Avramovic22e99c42019-06-05 14:03:13 +0000579 case G_FCMP: {
580 unsigned MipsFCMPCondCode;
581 bool isLogicallyNegated;
582 switch (CmpInst::Predicate Cond = static_cast<CmpInst::Predicate>(
583 I.getOperand(1).getPredicate())) {
584 case CmpInst::FCMP_UNO: // Unordered
585 case CmpInst::FCMP_ORD: // Ordered (OR)
586 MipsFCMPCondCode = Mips::FCOND_UN;
587 isLogicallyNegated = Cond != CmpInst::FCMP_UNO;
588 break;
589 case CmpInst::FCMP_OEQ: // Equal
590 case CmpInst::FCMP_UNE: // Not Equal (NEQ)
591 MipsFCMPCondCode = Mips::FCOND_OEQ;
592 isLogicallyNegated = Cond != CmpInst::FCMP_OEQ;
593 break;
594 case CmpInst::FCMP_UEQ: // Unordered or Equal
595 case CmpInst::FCMP_ONE: // Ordered or Greater Than or Less Than (OGL)
596 MipsFCMPCondCode = Mips::FCOND_UEQ;
597 isLogicallyNegated = Cond != CmpInst::FCMP_UEQ;
598 break;
599 case CmpInst::FCMP_OLT: // Ordered or Less Than
600 case CmpInst::FCMP_UGE: // Unordered or Greater Than or Equal (UGE)
601 MipsFCMPCondCode = Mips::FCOND_OLT;
602 isLogicallyNegated = Cond != CmpInst::FCMP_OLT;
603 break;
604 case CmpInst::FCMP_ULT: // Unordered or Less Than
605 case CmpInst::FCMP_OGE: // Ordered or Greater Than or Equal (OGE)
606 MipsFCMPCondCode = Mips::FCOND_ULT;
607 isLogicallyNegated = Cond != CmpInst::FCMP_ULT;
608 break;
609 case CmpInst::FCMP_OLE: // Ordered or Less Than or Equal
610 case CmpInst::FCMP_UGT: // Unordered or Greater Than (UGT)
611 MipsFCMPCondCode = Mips::FCOND_OLE;
612 isLogicallyNegated = Cond != CmpInst::FCMP_OLE;
613 break;
614 case CmpInst::FCMP_ULE: // Unordered or Less Than or Equal
615 case CmpInst::FCMP_OGT: // Ordered or Greater Than (OGT)
616 MipsFCMPCondCode = Mips::FCOND_ULE;
617 isLogicallyNegated = Cond != CmpInst::FCMP_ULE;
618 break;
619 default:
620 return false;
621 }
622
623 // Default compare result in gpr register will be `true`.
624 // We will move `false` (MIPS::Zero) to gpr result when fcmp gives false
625 // using MOVF_I. When orignal predicate (Cond) is logically negated
626 // MipsFCMPCondCode, result is inverted i.e. MOVT_I is used.
627 unsigned MoveOpcode = isLogicallyNegated ? Mips::MOVT_I : Mips::MOVF_I;
628
629 unsigned TrueInReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
630 BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
631 .addDef(TrueInReg)
632 .addUse(Mips::ZERO)
633 .addImm(1);
634
635 unsigned Size = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
636 unsigned FCMPOpcode =
637 Size == 32 ? Mips::FCMP_S32
638 : STI.isFP64bit() ? Mips::FCMP_D64 : Mips::FCMP_D32;
639 MachineInstr *FCMP = BuildMI(MBB, I, I.getDebugLoc(), TII.get(FCMPOpcode))
640 .addUse(I.getOperand(2).getReg())
641 .addUse(I.getOperand(3).getReg())
642 .addImm(MipsFCMPCondCode);
643 if (!constrainSelectedInstRegOperands(*FCMP, TII, TRI, RBI))
644 return false;
645
646 MachineInstr *Move = BuildMI(MBB, I, I.getDebugLoc(), TII.get(MoveOpcode))
647 .addDef(I.getOperand(0).getReg())
648 .addUse(Mips::ZERO)
649 .addUse(Mips::FCC0)
650 .addUse(TrueInReg);
651 if (!constrainSelectedInstRegOperands(*Move, TII, TRI, RBI))
652 return false;
653
654 I.eraseFromParent();
655 return true;
656 }
Petar Jovanovic021e4c82018-07-16 13:29:32 +0000657 default:
658 return false;
659 }
660
661 I.eraseFromParent();
662 return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
Petar Jovanovicfac93e22018-02-23 11:06:40 +0000663}
664
665namespace llvm {
666InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
667 MipsSubtarget &Subtarget,
668 MipsRegisterBankInfo &RBI) {
669 return new MipsInstructionSelector(TM, Subtarget, RBI);
670}
671} // end namespace llvm