MipsFastISel.cpp revision dce4a407a24b04eebc6a376f8e62b41aaa7b071f
1//===-- MipsastISel.cpp - Mips FastISel implementation
2//---------------------===//
3
4#include "llvm/CodeGen/FunctionLoweringInfo.h"
5#include "llvm/CodeGen/FastISel.h"
6#include "llvm/CodeGen/MachineInstrBuilder.h"
7#include "llvm/IR/GlobalAlias.h"
8#include "llvm/IR/GlobalVariable.h"
9#include "llvm/Target/TargetInstrInfo.h"
10#include "llvm/Target/TargetLibraryInfo.h"
11#include "MipsRegisterInfo.h"
12#include "MipsISelLowering.h"
13#include "MipsMachineFunction.h"
14#include "MipsSubtarget.h"
15
16using namespace llvm;
17
18namespace {
19
20// All possible address modes.
21typedef struct Address {
22  enum { RegBase, FrameIndexBase } BaseType;
23
24  union {
25    unsigned Reg;
26    int FI;
27  } Base;
28
29  int64_t Offset;
30
31  // Innocuous defaults for our address.
32  Address() : BaseType(RegBase), Offset(0) { Base.Reg = 0; }
33} Address;
34
35class MipsFastISel final : public FastISel {
36
37  /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can
38  /// make the right decision when generating code for different targets.
39  const MipsSubtarget *Subtarget;
40  Module &M;
41  const TargetMachine &TM;
42  const TargetInstrInfo &TII;
43  const TargetLowering &TLI;
44  MipsFunctionInfo *MFI;
45
46  // Convenience variables to avoid some queries.
47  LLVMContext *Context;
48
49  bool TargetSupported;
50
51public:
52  explicit MipsFastISel(FunctionLoweringInfo &funcInfo,
53                        const TargetLibraryInfo *libInfo)
54      : FastISel(funcInfo, libInfo),
55        M(const_cast<Module &>(*funcInfo.Fn->getParent())),
56        TM(funcInfo.MF->getTarget()), TII(*TM.getInstrInfo()),
57        TLI(*TM.getTargetLowering()) {
58    Subtarget = &TM.getSubtarget<MipsSubtarget>();
59    MFI = funcInfo.MF->getInfo<MipsFunctionInfo>();
60    Context = &funcInfo.Fn->getContext();
61    TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) &&
62                       (Subtarget->hasMips32r2() && (Subtarget->isABI_O32())));
63  }
64
65  bool TargetSelectInstruction(const Instruction *I) override;
66  unsigned TargetMaterializeConstant(const Constant *C) override;
67
68  bool ComputeAddress(const Value *Obj, Address &Addr);
69
70private:
71  bool EmitStore(MVT VT, unsigned SrcReg, Address &Addr,
72                 unsigned Alignment = 0);
73  bool SelectRet(const Instruction *I);
74  bool SelectStore(const Instruction *I);
75
76  bool isTypeLegal(Type *Ty, MVT &VT);
77  bool isLoadTypeLegal(Type *Ty, MVT &VT);
78
79  unsigned MaterializeFP(const ConstantFP *CFP, MVT VT);
80  unsigned MaterializeGV(const GlobalValue *GV, MVT VT);
81  unsigned MaterializeInt(const Constant *C, MVT VT);
82  unsigned Materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC);
83};
84
85bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) {
86  EVT evt = TLI.getValueType(Ty, true);
87  // Only handle simple types.
88  if (evt == MVT::Other || !evt.isSimple())
89    return false;
90  VT = evt.getSimpleVT();
91
92  // Handle all legal types, i.e. a register that will directly hold this
93  // value.
94  return TLI.isTypeLegal(VT);
95}
96
97bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) {
98  if (isTypeLegal(Ty, VT))
99    return true;
100  // We will extend this in a later patch:
101  //   If this is a type than can be sign or zero-extended to a basic operation
102  //   go ahead and accept it now.
103  return false;
104}
105
106bool MipsFastISel::ComputeAddress(const Value *Obj, Address &Addr) {
107  // This construct looks a big awkward but it is how other ports handle this
108  // and as this function is more fully completed, these cases which
109  // return false will have additional code in them.
110  //
111  if (isa<Instruction>(Obj))
112    return false;
113  else if (isa<ConstantExpr>(Obj))
114    return false;
115  Addr.Base.Reg = getRegForValue(Obj);
116  return Addr.Base.Reg != 0;
117}
118
119// Materialize a constant into a register, and return the register
120// number (or zero if we failed to handle it).
121unsigned MipsFastISel::TargetMaterializeConstant(const Constant *C) {
122  EVT CEVT = TLI.getValueType(C->getType(), true);
123
124  // Only handle simple types.
125  if (!CEVT.isSimple())
126    return 0;
127  MVT VT = CEVT.getSimpleVT();
128
129  if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C))
130    return MaterializeFP(CFP, VT);
131  else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
132    return MaterializeGV(GV, VT);
133  else if (isa<ConstantInt>(C))
134    return MaterializeInt(C, VT);
135
136  return 0;
137}
138
139bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr,
140                             unsigned Alignment) {
141  //
142  // more cases will be handled here in following patches.
143  //
144  if (VT != MVT::i32)
145    return false;
146  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::SW))
147      .addReg(SrcReg)
148      .addReg(Addr.Base.Reg)
149      .addImm(Addr.Offset);
150  return true;
151}
152
153bool MipsFastISel::SelectStore(const Instruction *I) {
154  Value *Op0 = I->getOperand(0);
155  unsigned SrcReg = 0;
156
157  // Atomic stores need special handling.
158  if (cast<StoreInst>(I)->isAtomic())
159    return false;
160
161  // Verify we have a legal type before going any further.
162  MVT VT;
163  if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT))
164    return false;
165
166  // Get the value to be stored into a register.
167  SrcReg = getRegForValue(Op0);
168  if (SrcReg == 0)
169    return false;
170
171  // See if we can handle this address.
172  Address Addr;
173  if (!ComputeAddress(I->getOperand(1), Addr))
174    return false;
175
176  if (!EmitStore(VT, SrcReg, Addr, cast<StoreInst>(I)->getAlignment()))
177    return false;
178  return true;
179}
180
181bool MipsFastISel::SelectRet(const Instruction *I) {
182  const ReturnInst *Ret = cast<ReturnInst>(I);
183
184  if (!FuncInfo.CanLowerReturn)
185    return false;
186  if (Ret->getNumOperands() > 0) {
187    return false;
188  }
189  unsigned RetOpc = Mips::RetRA;
190  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(RetOpc));
191  return true;
192}
193
194bool MipsFastISel::TargetSelectInstruction(const Instruction *I) {
195  if (!TargetSupported)
196    return false;
197  switch (I->getOpcode()) {
198  default:
199    break;
200  case Instruction::Store:
201    return SelectStore(I);
202  case Instruction::Ret:
203    return SelectRet(I);
204  }
205  return false;
206}
207}
208
209unsigned MipsFastISel::MaterializeFP(const ConstantFP *CFP, MVT VT) {
210  return 0;
211}
212
213unsigned MipsFastISel::MaterializeGV(const GlobalValue *GV, MVT VT) {
214  // For now 32-bit only.
215  if (VT != MVT::i32)
216    return 0;
217  const TargetRegisterClass *RC = &Mips::GPR32RegClass;
218  unsigned DestReg = createResultReg(RC);
219  const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
220  bool IsThreadLocal = GVar && GVar->isThreadLocal();
221  // TLS not supported at this time.
222  if (IsThreadLocal)
223    return 0;
224  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LW), DestReg)
225      .addReg(MFI->getGlobalBaseReg())
226      .addGlobalAddress(GV, 0, MipsII::MO_GOT);
227  return DestReg;
228}
229unsigned MipsFastISel::MaterializeInt(const Constant *C, MVT VT) {
230  if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1)
231    return 0;
232  const TargetRegisterClass *RC = &Mips::GPR32RegClass;
233  const ConstantInt *CI = cast<ConstantInt>(C);
234  int64_t Imm;
235  if (CI->isNegative())
236    Imm = CI->getSExtValue();
237  else
238    Imm = CI->getZExtValue();
239  return Materialize32BitInt(Imm, RC);
240}
241
242unsigned MipsFastISel::Materialize32BitInt(int64_t Imm,
243                                           const TargetRegisterClass *RC) {
244  unsigned ResultReg = createResultReg(RC);
245
246  if (isInt<16>(Imm)) {
247    unsigned Opc = Mips::ADDiu;
248    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
249        .addReg(Mips::ZERO)
250        .addImm(Imm);
251    return ResultReg;
252  } else if (isUInt<16>(Imm)) {
253    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::ORi),
254            ResultReg)
255        .addReg(Mips::ZERO)
256        .addImm(Imm);
257    return ResultReg;
258  }
259  unsigned Lo = Imm & 0xFFFF;
260  unsigned Hi = (Imm >> 16) & 0xFFFF;
261  if (Lo) {
262    // Both Lo and Hi have nonzero bits.
263    unsigned TmpReg = createResultReg(RC);
264    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LUi),
265            TmpReg).addImm(Hi);
266    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::ORi),
267            ResultReg)
268        .addReg(TmpReg)
269        .addImm(Lo);
270
271  } else {
272    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LUi),
273            ResultReg).addImm(Hi);
274  }
275  return ResultReg;
276}
277
278namespace llvm {
279FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo,
280                               const TargetLibraryInfo *libInfo) {
281  return new MipsFastISel(funcInfo, libInfo);
282}
283}
284