]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp
MFC r234353:
[FreeBSD/stable/9.git] / contrib / llvm / lib / Target / Mips / MipsMCInstLower.cpp
1 //===-- MipsMCInstLower.cpp - Convert Mips MachineInstr to MCInst ---------===//
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 //
10 // This file contains code to lower Mips MachineInstrs to their corresponding
11 // MCInst records.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "MipsMCInstLower.h"
16 #include "MipsAsmPrinter.h"
17 #include "MipsInstrInfo.h"
18 #include "MCTargetDesc/MipsBaseInfo.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/MachineInstr.h"
21 #include "llvm/CodeGen/MachineOperand.h"
22 #include "llvm/MC/MCContext.h"
23 #include "llvm/MC/MCExpr.h"
24 #include "llvm/MC/MCInst.h"
25 #include "llvm/Target/Mangler.h"
26
27 using namespace llvm;
28
29 MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter)
30   : AsmPrinter(asmprinter) {}
31
32 void MipsMCInstLower::Initialize(Mangler *M, MCContext* C) {
33   Mang = M;
34   Ctx = C;
35 }
36
37 MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
38                                               MachineOperandType MOTy,
39                                               unsigned Offset) const {
40   MCSymbolRefExpr::VariantKind Kind;
41   const MCSymbol *Symbol;
42
43   switch(MO.getTargetFlags()) {
44   default:                   llvm_unreachable("Invalid target flag!");
45   case MipsII::MO_NO_FLAG:   Kind = MCSymbolRefExpr::VK_None; break;
46   case MipsII::MO_GPREL:     Kind = MCSymbolRefExpr::VK_Mips_GPREL; break;
47   case MipsII::MO_GOT_CALL:  Kind = MCSymbolRefExpr::VK_Mips_GOT_CALL; break;
48   case MipsII::MO_GOT16:     Kind = MCSymbolRefExpr::VK_Mips_GOT16; break;
49   case MipsII::MO_GOT:       Kind = MCSymbolRefExpr::VK_Mips_GOT; break;
50   case MipsII::MO_ABS_HI:    Kind = MCSymbolRefExpr::VK_Mips_ABS_HI; break;
51   case MipsII::MO_ABS_LO:    Kind = MCSymbolRefExpr::VK_Mips_ABS_LO; break;
52   case MipsII::MO_TLSGD:     Kind = MCSymbolRefExpr::VK_Mips_TLSGD; break;
53   case MipsII::MO_TLSLDM:    Kind = MCSymbolRefExpr::VK_Mips_TLSLDM; break;
54   case MipsII::MO_DTPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_HI; break;
55   case MipsII::MO_DTPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_LO; break;
56   case MipsII::MO_GOTTPREL:  Kind = MCSymbolRefExpr::VK_Mips_GOTTPREL; break;
57   case MipsII::MO_TPREL_HI:  Kind = MCSymbolRefExpr::VK_Mips_TPREL_HI; break;
58   case MipsII::MO_TPREL_LO:  Kind = MCSymbolRefExpr::VK_Mips_TPREL_LO; break;
59   case MipsII::MO_GPOFF_HI:  Kind = MCSymbolRefExpr::VK_Mips_GPOFF_HI; break;
60   case MipsII::MO_GPOFF_LO:  Kind = MCSymbolRefExpr::VK_Mips_GPOFF_LO; break;
61   case MipsII::MO_GOT_DISP:  Kind = MCSymbolRefExpr::VK_Mips_GOT_DISP; break;
62   case MipsII::MO_GOT_PAGE:  Kind = MCSymbolRefExpr::VK_Mips_GOT_PAGE; break;
63   case MipsII::MO_GOT_OFST:  Kind = MCSymbolRefExpr::VK_Mips_GOT_OFST; break;
64   }
65
66   switch (MOTy) {
67   case MachineOperand::MO_MachineBasicBlock:
68     Symbol = MO.getMBB()->getSymbol();
69     break;
70
71   case MachineOperand::MO_GlobalAddress:
72     Symbol = Mang->getSymbol(MO.getGlobal());
73     break;
74
75   case MachineOperand::MO_BlockAddress:
76     Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress());
77     break;
78
79   case MachineOperand::MO_ExternalSymbol:
80     Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName());
81     break;
82
83   case MachineOperand::MO_JumpTableIndex:
84     Symbol = AsmPrinter.GetJTISymbol(MO.getIndex());
85     break;
86
87   case MachineOperand::MO_ConstantPoolIndex:
88     Symbol = AsmPrinter.GetCPISymbol(MO.getIndex());
89     if (MO.getOffset())
90       Offset += MO.getOffset();
91     break;
92
93   default:
94     llvm_unreachable("<unknown operand type>");
95   }
96
97   const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, Kind, *Ctx);
98
99   if (!Offset)
100     return MCOperand::CreateExpr(MCSym);
101
102   // Assume offset is never negative.
103   assert(Offset > 0);
104
105   const MCConstantExpr *OffsetExpr =  MCConstantExpr::Create(Offset, *Ctx);
106   const MCBinaryExpr *AddExpr = MCBinaryExpr::CreateAdd(MCSym, OffsetExpr, *Ctx);
107   return MCOperand::CreateExpr(AddExpr);
108 }
109
110 static void CreateMCInst(MCInst& Inst, unsigned Opc, const MCOperand& Opnd0,
111                          const MCOperand& Opnd1,
112                          const MCOperand& Opnd2 = MCOperand()) {
113   Inst.setOpcode(Opc);
114   Inst.addOperand(Opnd0);
115   Inst.addOperand(Opnd1);
116   if (Opnd2.isValid())
117     Inst.addOperand(Opnd2);
118 }
119
120 // Lower ".cpload $reg" to
121 //  "lui   $gp, %hi(_gp_disp)"
122 //  "addiu $gp, $gp, %lo(_gp_disp)"
123 //  "addu  $gp, $gp, $t9"
124 void MipsMCInstLower::LowerCPLOAD(SmallVector<MCInst, 4>& MCInsts) {
125   MCOperand GPReg = MCOperand::CreateReg(Mips::GP);
126   MCOperand T9Reg = MCOperand::CreateReg(Mips::T9);
127   StringRef SymName("_gp_disp");
128   const MCSymbol *Sym = Ctx->GetOrCreateSymbol(SymName);
129   const MCSymbolRefExpr *MCSym;
130
131   MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_HI, *Ctx);
132   MCOperand SymHi = MCOperand::CreateExpr(MCSym);
133   MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_LO, *Ctx);
134   MCOperand SymLo = MCOperand::CreateExpr(MCSym);
135
136   MCInsts.resize(3);
137
138   CreateMCInst(MCInsts[0], Mips::LUi, GPReg, SymHi);
139   CreateMCInst(MCInsts[1], Mips::ADDiu, GPReg, GPReg, SymLo);
140   CreateMCInst(MCInsts[2], Mips::ADDu, GPReg, GPReg, T9Reg);
141 }
142
143 // Lower ".cprestore offset" to "sw $gp, offset($sp)".
144 void MipsMCInstLower::LowerCPRESTORE(int64_t Offset,
145                                      SmallVector<MCInst, 4>& MCInsts) {
146   assert(isInt<32>(Offset) && (Offset >= 0) &&
147          "Imm operand of .cprestore must be a non-negative 32-bit value.");
148
149   MCOperand SPReg = MCOperand::CreateReg(Mips::SP), BaseReg = SPReg;
150   MCOperand GPReg = MCOperand::CreateReg(Mips::GP);
151
152   if (!isInt<16>(Offset)) {
153     unsigned Hi = ((Offset + 0x8000) >> 16) & 0xffff;
154     Offset &= 0xffff;
155     MCOperand ATReg = MCOperand::CreateReg(Mips::AT);
156     BaseReg = ATReg;
157
158     // lui   at,hi
159     // addu  at,at,sp
160     MCInsts.resize(2);
161     CreateMCInst(MCInsts[0], Mips::LUi, ATReg, MCOperand::CreateImm(Hi));
162     CreateMCInst(MCInsts[1], Mips::ADDu, ATReg, ATReg, SPReg);
163   }
164
165   MCInst Sw;
166   CreateMCInst(Sw, Mips::SW, GPReg, BaseReg, MCOperand::CreateImm(Offset));
167   MCInsts.push_back(Sw);
168 }
169
170 MCOperand MipsMCInstLower::LowerOperand(const MachineOperand& MO,
171                                         unsigned offset) const {
172   MachineOperandType MOTy = MO.getType();
173
174   switch (MOTy) {
175   default: llvm_unreachable("unknown operand type");
176   case MachineOperand::MO_Register:
177     // Ignore all implicit register operands.
178     if (MO.isImplicit()) break;
179     return MCOperand::CreateReg(MO.getReg());
180   case MachineOperand::MO_Immediate:
181     return MCOperand::CreateImm(MO.getImm() + offset);
182   case MachineOperand::MO_MachineBasicBlock:
183   case MachineOperand::MO_GlobalAddress:
184   case MachineOperand::MO_ExternalSymbol:
185   case MachineOperand::MO_JumpTableIndex:
186   case MachineOperand::MO_ConstantPoolIndex:
187   case MachineOperand::MO_BlockAddress:
188     return LowerSymbolOperand(MO, MOTy, offset);
189   case MachineOperand::MO_RegisterMask:
190     break;
191  }
192
193   return MCOperand();
194 }
195
196 void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
197   OutMI.setOpcode(MI->getOpcode());
198
199   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
200     const MachineOperand &MO = MI->getOperand(i);
201     MCOperand MCOp = LowerOperand(MO);
202
203     if (MCOp.isValid())
204       OutMI.addOperand(MCOp);
205   }
206 }
207
208 void MipsMCInstLower::LowerUnalignedLoadStore(const MachineInstr *MI,
209                                               SmallVector<MCInst,
210                                               4>& MCInsts) {
211   unsigned Opc = MI->getOpcode();
212   MCInst Instr1, Instr2, Instr3, Move;
213
214   bool TwoInstructions = false;
215
216   assert(MI->getNumOperands() == 3);
217   assert(MI->getOperand(0).isReg());
218   assert(MI->getOperand(1).isReg());
219
220   MCOperand Target = LowerOperand(MI->getOperand(0));
221   MCOperand Base = LowerOperand(MI->getOperand(1));
222   MCOperand ATReg = MCOperand::CreateReg(Mips::AT);
223   MCOperand ZeroReg = MCOperand::CreateReg(Mips::ZERO);
224
225   MachineOperand UnLoweredName = MI->getOperand(2);
226   MCOperand Name = LowerOperand(UnLoweredName);
227
228   Move.setOpcode(Mips::ADDu);
229   Move.addOperand(Target);
230   Move.addOperand(ATReg);
231   Move.addOperand(ZeroReg);
232
233   switch (Opc) {
234   case Mips::ULW: {
235     // FIXME: only works for little endian right now
236     MCOperand AdjName = LowerOperand(UnLoweredName, 3);
237     if (Base.getReg() == (Target.getReg())) {
238       Instr1.setOpcode(Mips::LWL);
239       Instr1.addOperand(ATReg);
240       Instr1.addOperand(Base);
241       Instr1.addOperand(AdjName);
242       Instr2.setOpcode(Mips::LWR);
243       Instr2.addOperand(ATReg);
244       Instr2.addOperand(Base);
245       Instr2.addOperand(Name);
246       Instr3 = Move;
247     } else {
248       TwoInstructions = true;
249       Instr1.setOpcode(Mips::LWL);
250       Instr1.addOperand(Target);
251       Instr1.addOperand(Base);
252       Instr1.addOperand(AdjName);
253       Instr2.setOpcode(Mips::LWR);
254       Instr2.addOperand(Target);
255       Instr2.addOperand(Base);
256       Instr2.addOperand(Name);
257     }
258     break;
259   }
260   case Mips::ULHu: {
261     // FIXME: only works for little endian right now
262     MCOperand AdjName = LowerOperand(UnLoweredName, 1);
263     Instr1.setOpcode(Mips::LBu);
264     Instr1.addOperand(ATReg);
265     Instr1.addOperand(Base);
266     Instr1.addOperand(AdjName);
267     Instr2.setOpcode(Mips::LBu);
268     Instr2.addOperand(Target);
269     Instr2.addOperand(Base);
270     Instr2.addOperand(Name);
271     Instr3.setOpcode(Mips::INS);
272     Instr3.addOperand(Target);
273     Instr3.addOperand(ATReg);
274     Instr3.addOperand(MCOperand::CreateImm(0x8));
275     Instr3.addOperand(MCOperand::CreateImm(0x18));
276     break;
277   }
278
279   case Mips::USW: {
280     // FIXME: only works for little endian right now
281     assert (Base.getReg() != Target.getReg());
282     TwoInstructions = true;
283     MCOperand AdjName = LowerOperand(UnLoweredName, 3);
284     Instr1.setOpcode(Mips::SWL);
285     Instr1.addOperand(Target);
286     Instr1.addOperand(Base);
287     Instr1.addOperand(AdjName);
288     Instr2.setOpcode(Mips::SWR);
289     Instr2.addOperand(Target);
290     Instr2.addOperand(Base);
291     Instr2.addOperand(Name);
292     break;
293   }
294   case Mips::USH: {
295     MCOperand AdjName = LowerOperand(UnLoweredName, 1);
296     Instr1.setOpcode(Mips::SB);
297     Instr1.addOperand(Target);
298     Instr1.addOperand(Base);
299     Instr1.addOperand(Name);
300     Instr2.setOpcode(Mips::SRL);
301     Instr2.addOperand(ATReg);
302     Instr2.addOperand(Target);
303     Instr2.addOperand(MCOperand::CreateImm(8));
304     Instr3.setOpcode(Mips::SB);
305     Instr3.addOperand(ATReg);
306     Instr3.addOperand(Base);
307     Instr3.addOperand(AdjName);
308     break;
309   }
310   default:
311     // FIXME: need to add others
312     llvm_unreachable("unaligned instruction not processed");
313   }
314
315   MCInsts.push_back(Instr1);
316   MCInsts.push_back(Instr2);
317   if (!TwoInstructions) MCInsts.push_back(Instr3);
318 }
319
320 // Convert
321 //  "setgp01 $reg"
322 // to
323 //  "lui   $reg, %hi(_gp_disp)"
324 //  "addiu $reg, $reg, %lo(_gp_disp)"
325 void MipsMCInstLower::LowerSETGP01(const MachineInstr *MI,
326                                    SmallVector<MCInst, 4>& MCInsts) {
327   const MachineOperand &MO = MI->getOperand(0);
328   assert(MO.isReg());
329   MCOperand RegOpnd = MCOperand::CreateReg(MO.getReg());
330   StringRef SymName("_gp_disp");
331   const MCSymbol *Sym = Ctx->GetOrCreateSymbol(SymName);
332   const MCSymbolRefExpr *MCSym;
333
334   MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_HI, *Ctx);
335   MCOperand SymHi = MCOperand::CreateExpr(MCSym);
336   MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_LO, *Ctx);
337   MCOperand SymLo = MCOperand::CreateExpr(MCSym);
338
339   MCInsts.resize(2);
340
341   CreateMCInst(MCInsts[0], Mips::LUi, RegOpnd, SymHi);
342   CreateMCInst(MCInsts[1], Mips::ADDiu, RegOpnd, RegOpnd, SymLo);
343 }