blob: e5857a0100e4d2061af837f72faf04553ee1e617 [file] [log] [blame]
Reed Kotler720c5ca2014-04-17 22:15:34 +00001//===-- MipsastISel.cpp - Mips FastISel implementation
2//---------------------===//
3
4#include "llvm/CodeGen/FunctionLoweringInfo.h"
5#include "llvm/CodeGen/FastISel.h"
Reed Kotler67077b32014-04-29 17:57:50 +00006#include "llvm/CodeGen/MachineInstrBuilder.h"
Reed Kotlerbab3f232014-05-01 20:39:21 +00007#include "llvm/IR/GlobalAlias.h"
8#include "llvm/IR/GlobalVariable.h"
Reed Kotler67077b32014-04-29 17:57:50 +00009#include "llvm/Target/TargetInstrInfo.h"
Reed Kotler720c5ca2014-04-17 22:15:34 +000010#include "llvm/Target/TargetLibraryInfo.h"
Reed Kotlerbab3f232014-05-01 20:39:21 +000011#include "MipsRegisterInfo.h"
Reed Kotler720c5ca2014-04-17 22:15:34 +000012#include "MipsISelLowering.h"
Reed Kotler67077b32014-04-29 17:57:50 +000013#include "MipsMachineFunction.h"
14#include "MipsSubtarget.h"
Reed Kotler9fe25f32014-06-08 02:08:43 +000015#include "MipsTargetMachine.h"
Reed Kotler720c5ca2014-04-17 22:15:34 +000016
17using namespace llvm;
18
19namespace {
20
Reed Kotlerbab3f232014-05-01 20:39:21 +000021// All possible address modes.
22typedef struct Address {
23 enum { RegBase, FrameIndexBase } BaseType;
24
25 union {
26 unsigned Reg;
27 int FI;
28 } Base;
29
30 int64_t Offset;
31
32 // Innocuous defaults for our address.
33 Address() : BaseType(RegBase), Offset(0) { Base.Reg = 0; }
34} Address;
35
Reed Kotler720c5ca2014-04-17 22:15:34 +000036class MipsFastISel final : public FastISel {
37
Reed Kotler67077b32014-04-29 17:57:50 +000038 /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can
39 /// make the right decision when generating code for different targets.
Reed Kotler67077b32014-04-29 17:57:50 +000040 Module &M;
41 const TargetMachine &TM;
42 const TargetInstrInfo &TII;
43 const TargetLowering &TLI;
Eric Christopher22405e42014-07-10 17:26:51 +000044 const MipsSubtarget *Subtarget;
Reed Kotler67077b32014-04-29 17:57:50 +000045 MipsFunctionInfo *MFI;
46
47 // Convenience variables to avoid some queries.
48 LLVMContext *Context;
49
50 bool TargetSupported;
51
Reed Kotler720c5ca2014-04-17 22:15:34 +000052public:
53 explicit MipsFastISel(FunctionLoweringInfo &funcInfo,
54 const TargetLibraryInfo *libInfo)
Reed Kotler67077b32014-04-29 17:57:50 +000055 : FastISel(funcInfo, libInfo),
56 M(const_cast<Module &>(*funcInfo.Fn->getParent())),
Eric Christopherd9134482014-08-04 21:25:23 +000057 TM(funcInfo.MF->getTarget()),
58 TII(*TM.getSubtargetImpl()->getInstrInfo()),
59 TLI(*TM.getSubtargetImpl()->getTargetLowering()),
Eric Christopher22405e42014-07-10 17:26:51 +000060 Subtarget(&TM.getSubtarget<MipsSubtarget>()) {
Reed Kotler67077b32014-04-29 17:57:50 +000061 MFI = funcInfo.MF->getInfo<MipsFunctionInfo>();
62 Context = &funcInfo.Fn->getContext();
Eric Christopher22405e42014-07-10 17:26:51 +000063 TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) &&
Reed Kotler32be74b2014-09-15 20:30:25 +000064 ((Subtarget->hasMips32r2() || Subtarget->hasMips32()) &&
65 (Subtarget->isABI_O32())));
Reed Kotler67077b32014-04-29 17:57:50 +000066 }
67
Juergen Ributzka5b8bb4d2014-09-03 20:56:52 +000068 bool fastSelectInstruction(const Instruction *I) override;
69 unsigned fastMaterializeConstant(const Constant *C) override;
Reed Kotler67077b32014-04-29 17:57:50 +000070
Reed Kotlerbab3f232014-05-01 20:39:21 +000071 bool ComputeAddress(const Value *Obj, Address &Addr);
72
73private:
Reed Kotler9fe3bfd2014-06-16 22:05:47 +000074 bool EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
75 unsigned Alignment = 0);
Reed Kotlerbab3f232014-05-01 20:39:21 +000076 bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr,
77 unsigned Alignment = 0);
Reed Kotler9fe3bfd2014-06-16 22:05:47 +000078 bool SelectLoad(const Instruction *I);
Reed Kotler67077b32014-04-29 17:57:50 +000079 bool SelectRet(const Instruction *I);
Reed Kotlerbab3f232014-05-01 20:39:21 +000080 bool SelectStore(const Instruction *I);
81
82 bool isTypeLegal(Type *Ty, MVT &VT);
83 bool isLoadTypeLegal(Type *Ty, MVT &VT);
84
85 unsigned MaterializeFP(const ConstantFP *CFP, MVT VT);
86 unsigned MaterializeGV(const GlobalValue *GV, MVT VT);
87 unsigned MaterializeInt(const Constant *C, MVT VT);
Reed Kotler6280d972014-05-15 21:54:15 +000088 unsigned Materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC);
Reed Kotler9fe25f32014-06-08 02:08:43 +000089
90 // for some reason, this default is not generated by tablegen
Reed Kotlerfb77bc92014-06-08 03:04:42 +000091 // so we explicitly generate it here.
Reed Kotler9fe25f32014-06-08 02:08:43 +000092 //
Juergen Ributzka88e32512014-09-03 20:56:59 +000093 unsigned fastEmitInst_riir(uint64_t inst, const TargetRegisterClass *RC,
Reed Kotler9fe25f32014-06-08 02:08:43 +000094 unsigned Op0, bool Op0IsKill, uint64_t imm1,
95 uint64_t imm2, unsigned Op3, bool Op3IsKill) {
96 return 0;
97 }
98
Reed Kotlerfb77bc92014-06-08 03:04:42 +000099 MachineInstrBuilder EmitInst(unsigned Opc) {
100 return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
101 }
102
103 MachineInstrBuilder EmitInst(unsigned Opc, unsigned DstReg) {
104 return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
105 DstReg);
106 }
107
108 MachineInstrBuilder EmitInstStore(unsigned Opc, unsigned SrcReg,
109 unsigned MemReg, int64_t MemOffset) {
110 return EmitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset);
111 }
112
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000113 MachineInstrBuilder EmitInstLoad(unsigned Opc, unsigned DstReg,
Reed Kotler87048a42014-08-07 22:09:01 +0000114 unsigned MemReg, int64_t MemOffset) {
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000115 return EmitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset);
116 }
117
Reed Kotler9fe25f32014-06-08 02:08:43 +0000118#include "MipsGenFastISel.inc"
Reed Kotler720c5ca2014-04-17 22:15:34 +0000119};
Reed Kotler67077b32014-04-29 17:57:50 +0000120
Reed Kotlerbab3f232014-05-01 20:39:21 +0000121bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) {
122 EVT evt = TLI.getValueType(Ty, true);
123 // Only handle simple types.
124 if (evt == MVT::Other || !evt.isSimple())
125 return false;
126 VT = evt.getSimpleVT();
127
128 // Handle all legal types, i.e. a register that will directly hold this
129 // value.
130 return TLI.isTypeLegal(VT);
131}
132
133bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) {
134 if (isTypeLegal(Ty, VT))
135 return true;
136 // We will extend this in a later patch:
137 // If this is a type than can be sign or zero-extended to a basic operation
138 // go ahead and accept it now.
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000139 if (VT == MVT::i8 || VT == MVT::i16)
140 return true;
Reed Kotlerbab3f232014-05-01 20:39:21 +0000141 return false;
142}
143
144bool MipsFastISel::ComputeAddress(const Value *Obj, Address &Addr) {
145 // This construct looks a big awkward but it is how other ports handle this
146 // and as this function is more fully completed, these cases which
147 // return false will have additional code in them.
148 //
149 if (isa<Instruction>(Obj))
150 return false;
151 else if (isa<ConstantExpr>(Obj))
152 return false;
153 Addr.Base.Reg = getRegForValue(Obj);
154 return Addr.Base.Reg != 0;
155}
156
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000157bool MipsFastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
158 unsigned Alignment) {
159 //
160 // more cases will be handled here in following patches.
161 //
162 unsigned Opc;
163 switch (VT.SimpleTy) {
164 case MVT::i32: {
165 ResultReg = createResultReg(&Mips::GPR32RegClass);
166 Opc = Mips::LW;
167 break;
168 }
169 case MVT::i16: {
170 ResultReg = createResultReg(&Mips::GPR32RegClass);
171 Opc = Mips::LHu;
172 break;
173 }
174 case MVT::i8: {
175 ResultReg = createResultReg(&Mips::GPR32RegClass);
176 Opc = Mips::LBu;
177 break;
178 }
179 case MVT::f32: {
180 ResultReg = createResultReg(&Mips::FGR32RegClass);
181 Opc = Mips::LWC1;
182 break;
183 }
184 case MVT::f64: {
185 ResultReg = createResultReg(&Mips::AFGR64RegClass);
186 Opc = Mips::LDC1;
187 break;
188 }
189 default:
190 return false;
191 }
192 EmitInstLoad(Opc, ResultReg, Addr.Base.Reg, Addr.Offset);
193 return true;
194}
195
Reed Kotlerbab3f232014-05-01 20:39:21 +0000196// Materialize a constant into a register, and return the register
197// number (or zero if we failed to handle it).
Juergen Ributzka5b8bb4d2014-09-03 20:56:52 +0000198unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) {
Reed Kotlerbab3f232014-05-01 20:39:21 +0000199 EVT CEVT = TLI.getValueType(C->getType(), true);
200
201 // Only handle simple types.
202 if (!CEVT.isSimple())
203 return 0;
204 MVT VT = CEVT.getSimpleVT();
205
206 if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C))
207 return MaterializeFP(CFP, VT);
208 else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
209 return MaterializeGV(GV, VT);
210 else if (isa<ConstantInt>(C))
211 return MaterializeInt(C, VT);
212
213 return 0;
214}
215
216bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr,
217 unsigned Alignment) {
218 //
219 // more cases will be handled here in following patches.
220 //
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000221 unsigned Opc;
222 switch (VT.SimpleTy) {
223 case MVT::i8:
224 Opc = Mips::SB;
225 break;
226 case MVT::i16:
227 Opc = Mips::SH;
228 break;
229 case MVT::i32:
230 Opc = Mips::SW;
231 break;
232 case MVT::f32:
233 Opc = Mips::SWC1;
234 break;
235 case MVT::f64:
236 Opc = Mips::SDC1;
237 break;
238 default:
Reed Kotlerbab3f232014-05-01 20:39:21 +0000239 return false;
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000240 }
241 EmitInstStore(Opc, SrcReg, Addr.Base.Reg, Addr.Offset);
242 return true;
243}
244
245bool MipsFastISel::SelectLoad(const Instruction *I) {
246 // Atomic loads need special handling.
247 if (cast<LoadInst>(I)->isAtomic())
248 return false;
249
250 // Verify we have a legal type before going any further.
251 MVT VT;
252 if (!isLoadTypeLegal(I->getType(), VT))
253 return false;
254
255 // See if we can handle this address.
256 Address Addr;
257 if (!ComputeAddress(I->getOperand(0), Addr))
258 return false;
259
260 unsigned ResultReg;
261 if (!EmitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment()))
262 return false;
Juergen Ributzka5b8bb4d2014-09-03 20:56:52 +0000263 updateValueMap(I, ResultReg);
Reed Kotlerbab3f232014-05-01 20:39:21 +0000264 return true;
265}
266
267bool MipsFastISel::SelectStore(const Instruction *I) {
268 Value *Op0 = I->getOperand(0);
269 unsigned SrcReg = 0;
270
271 // Atomic stores need special handling.
272 if (cast<StoreInst>(I)->isAtomic())
273 return false;
274
275 // Verify we have a legal type before going any further.
276 MVT VT;
277 if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT))
278 return false;
279
280 // Get the value to be stored into a register.
281 SrcReg = getRegForValue(Op0);
282 if (SrcReg == 0)
283 return false;
284
285 // See if we can handle this address.
286 Address Addr;
287 if (!ComputeAddress(I->getOperand(1), Addr))
288 return false;
289
290 if (!EmitStore(VT, SrcReg, Addr, cast<StoreInst>(I)->getAlignment()))
291 return false;
292 return true;
293}
294
Reed Kotler67077b32014-04-29 17:57:50 +0000295bool MipsFastISel::SelectRet(const Instruction *I) {
296 const ReturnInst *Ret = cast<ReturnInst>(I);
297
298 if (!FuncInfo.CanLowerReturn)
299 return false;
300 if (Ret->getNumOperands() > 0) {
301 return false;
302 }
Reed Kotlerfb77bc92014-06-08 03:04:42 +0000303 EmitInst(Mips::RetRA);
Reed Kotler67077b32014-04-29 17:57:50 +0000304 return true;
305}
306
Juergen Ributzka5b8bb4d2014-09-03 20:56:52 +0000307bool MipsFastISel::fastSelectInstruction(const Instruction *I) {
Reed Kotler67077b32014-04-29 17:57:50 +0000308 if (!TargetSupported)
309 return false;
310 switch (I->getOpcode()) {
311 default:
312 break;
Reed Kotler9fe3bfd2014-06-16 22:05:47 +0000313 case Instruction::Load:
314 return SelectLoad(I);
Reed Kotlerbab3f232014-05-01 20:39:21 +0000315 case Instruction::Store:
316 return SelectStore(I);
Reed Kotler67077b32014-04-29 17:57:50 +0000317 case Instruction::Ret:
318 return SelectRet(I);
319 }
320 return false;
321}
Reed Kotler720c5ca2014-04-17 22:15:34 +0000322}
323
Reed Kotlerbab3f232014-05-01 20:39:21 +0000324unsigned MipsFastISel::MaterializeFP(const ConstantFP *CFP, MVT VT) {
Reed Kotler063d4fb2014-06-10 16:45:44 +0000325 int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue();
326 if (VT == MVT::f32) {
327 const TargetRegisterClass *RC = &Mips::FGR32RegClass;
328 unsigned DestReg = createResultReg(RC);
329 unsigned TempReg = Materialize32BitInt(Imm, &Mips::GPR32RegClass);
330 EmitInst(Mips::MTC1, DestReg).addReg(TempReg);
331 return DestReg;
332 } else if (VT == MVT::f64) {
333 const TargetRegisterClass *RC = &Mips::AFGR64RegClass;
334 unsigned DestReg = createResultReg(RC);
335 unsigned TempReg1 = Materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass);
336 unsigned TempReg2 =
337 Materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass);
338 EmitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1);
339 return DestReg;
340 }
Reed Kotlerbab3f232014-05-01 20:39:21 +0000341 return 0;
342}
343
344unsigned MipsFastISel::MaterializeGV(const GlobalValue *GV, MVT VT) {
345 // For now 32-bit only.
346 if (VT != MVT::i32)
347 return 0;
348 const TargetRegisterClass *RC = &Mips::GPR32RegClass;
349 unsigned DestReg = createResultReg(RC);
350 const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
351 bool IsThreadLocal = GVar && GVar->isThreadLocal();
352 // TLS not supported at this time.
353 if (IsThreadLocal)
354 return 0;
Reed Kotlerfb77bc92014-06-08 03:04:42 +0000355 EmitInst(Mips::LW, DestReg).addReg(MFI->getGlobalBaseReg()).addGlobalAddress(
356 GV, 0, MipsII::MO_GOT);
Reed Kotler87048a42014-08-07 22:09:01 +0000357 if ((GV->hasInternalLinkage() ||
358 (GV->hasLocalLinkage() && !isa<Function>(GV)))) {
359 unsigned TempReg = createResultReg(RC);
360 EmitInst(Mips::ADDiu, TempReg).addReg(DestReg).addGlobalAddress(
361 GV, 0, MipsII::MO_ABS_LO);
362 DestReg = TempReg;
363 }
Reed Kotlerbab3f232014-05-01 20:39:21 +0000364 return DestReg;
365}
Reed Kotler87048a42014-08-07 22:09:01 +0000366
Reed Kotlerbab3f232014-05-01 20:39:21 +0000367unsigned MipsFastISel::MaterializeInt(const Constant *C, MVT VT) {
Reed Kotler6280d972014-05-15 21:54:15 +0000368 if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1)
Reed Kotlerbab3f232014-05-01 20:39:21 +0000369 return 0;
370 const TargetRegisterClass *RC = &Mips::GPR32RegClass;
Reed Kotlerbab3f232014-05-01 20:39:21 +0000371 const ConstantInt *CI = cast<ConstantInt>(C);
Reed Kotler6280d972014-05-15 21:54:15 +0000372 int64_t Imm;
Reed Kotler87048a42014-08-07 22:09:01 +0000373 if ((VT != MVT::i1) && CI->isNegative())
Reed Kotler6280d972014-05-15 21:54:15 +0000374 Imm = CI->getSExtValue();
375 else
376 Imm = CI->getZExtValue();
377 return Materialize32BitInt(Imm, RC);
378}
379
380unsigned MipsFastISel::Materialize32BitInt(int64_t Imm,
381 const TargetRegisterClass *RC) {
382 unsigned ResultReg = createResultReg(RC);
383
384 if (isInt<16>(Imm)) {
Reed Kotlerbab3f232014-05-01 20:39:21 +0000385 unsigned Opc = Mips::ADDiu;
Reed Kotlerfb77bc92014-06-08 03:04:42 +0000386 EmitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm);
Reed Kotler6280d972014-05-15 21:54:15 +0000387 return ResultReg;
388 } else if (isUInt<16>(Imm)) {
Reed Kotlerfb77bc92014-06-08 03:04:42 +0000389 EmitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm);
Reed Kotler6280d972014-05-15 21:54:15 +0000390 return ResultReg;
Reed Kotlerbab3f232014-05-01 20:39:21 +0000391 }
Reed Kotler6280d972014-05-15 21:54:15 +0000392 unsigned Lo = Imm & 0xFFFF;
393 unsigned Hi = (Imm >> 16) & 0xFFFF;
394 if (Lo) {
395 // Both Lo and Hi have nonzero bits.
396 unsigned TmpReg = createResultReg(RC);
Reed Kotlerfb77bc92014-06-08 03:04:42 +0000397 EmitInst(Mips::LUi, TmpReg).addImm(Hi);
398 EmitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo);
Reed Kotler6280d972014-05-15 21:54:15 +0000399 } else {
Reed Kotlerfb77bc92014-06-08 03:04:42 +0000400 EmitInst(Mips::LUi, ResultReg).addImm(Hi);
Reed Kotler6280d972014-05-15 21:54:15 +0000401 }
402 return ResultReg;
Reed Kotlerbab3f232014-05-01 20:39:21 +0000403}
404
Reed Kotler720c5ca2014-04-17 22:15:34 +0000405namespace llvm {
406FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo,
407 const TargetLibraryInfo *libInfo) {
408 return new MipsFastISel(funcInfo, libInfo);
409}
410}