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
27using namespace llvm;
28
29MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter)
30  : AsmPrinter(asmprinter) {}
31
32void MipsMCInstLower::Initialize(Mangler *M, MCContext* C) {
33  Mang = M;
34  Ctx = C;
35}
36
37MCOperand 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
110static 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"
124void 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)".
144void 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
170MCOperand 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
196void 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
208void 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)"
325void 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}
344