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