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#include "MipsMCInstLower.h"
15#include "MCTargetDesc/MipsBaseInfo.h"
16#include "MipsAsmPrinter.h"
17#include "MipsInstrInfo.h"
18#include "llvm/CodeGen/MachineFunction.h"
19#include "llvm/CodeGen/MachineInstr.h"
20#include "llvm/CodeGen/MachineOperand.h"
21#include "llvm/IR/Mangler.h"
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCInst.h"
25#include "llvm/MC/MCStreamer.h"
26
27using namespace llvm;
28
29MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter)
30  : AsmPrinter(asmprinter) {}
31
32void MipsMCInstLower::Initialize(MCContext *C) {
33  Ctx = C;
34}
35
36MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
37                                              MachineOperandType MOTy,
38                                              unsigned Offset) const {
39  MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
40  MipsMCExpr::MipsExprKind TargetKind = MipsMCExpr::MEK_None;
41  bool IsGpOff = false;
42  const MCSymbol *Symbol;
43
44  switch(MO.getTargetFlags()) {
45  default:
46    llvm_unreachable("Invalid target flag!");
47  case MipsII::MO_NO_FLAG:
48    break;
49  case MipsII::MO_GPREL:
50    TargetKind = MipsMCExpr::MEK_GPREL;
51    break;
52  case MipsII::MO_GOT_CALL:
53    TargetKind = MipsMCExpr::MEK_GOT_CALL;
54    break;
55  case MipsII::MO_GOT:
56    TargetKind = MipsMCExpr::MEK_GOT;
57    break;
58  case MipsII::MO_ABS_HI:
59    TargetKind = MipsMCExpr::MEK_HI;
60    break;
61  case MipsII::MO_ABS_LO:
62    TargetKind = MipsMCExpr::MEK_LO;
63    break;
64  case MipsII::MO_TLSGD:
65    TargetKind = MipsMCExpr::MEK_TLSGD;
66    break;
67  case MipsII::MO_TLSLDM:
68    TargetKind = MipsMCExpr::MEK_TLSLDM;
69    break;
70  case MipsII::MO_DTPREL_HI:
71    TargetKind = MipsMCExpr::MEK_DTPREL_HI;
72    break;
73  case MipsII::MO_DTPREL_LO:
74    TargetKind = MipsMCExpr::MEK_DTPREL_LO;
75    break;
76  case MipsII::MO_GOTTPREL:
77    TargetKind = MipsMCExpr::MEK_GOTTPREL;
78    break;
79  case MipsII::MO_TPREL_HI:
80    TargetKind = MipsMCExpr::MEK_TPREL_HI;
81    break;
82  case MipsII::MO_TPREL_LO:
83    TargetKind = MipsMCExpr::MEK_TPREL_LO;
84    break;
85  case MipsII::MO_GPOFF_HI:
86    TargetKind = MipsMCExpr::MEK_HI;
87    IsGpOff = true;
88    break;
89  case MipsII::MO_GPOFF_LO:
90    TargetKind = MipsMCExpr::MEK_LO;
91    IsGpOff = true;
92    break;
93  case MipsII::MO_GOT_DISP:
94    TargetKind = MipsMCExpr::MEK_GOT_DISP;
95    break;
96  case MipsII::MO_GOT_HI16:
97    TargetKind = MipsMCExpr::MEK_GOT_HI16;
98    break;
99  case MipsII::MO_GOT_LO16:
100    TargetKind = MipsMCExpr::MEK_GOT_LO16;
101    break;
102  case MipsII::MO_GOT_PAGE:
103    TargetKind = MipsMCExpr::MEK_GOT_PAGE;
104    break;
105  case MipsII::MO_GOT_OFST:
106    TargetKind = MipsMCExpr::MEK_GOT_OFST;
107    break;
108  case MipsII::MO_HIGHER:
109    TargetKind = MipsMCExpr::MEK_HIGHER;
110    break;
111  case MipsII::MO_HIGHEST:
112    TargetKind = MipsMCExpr::MEK_HIGHEST;
113    break;
114  case MipsII::MO_CALL_HI16:
115    TargetKind = MipsMCExpr::MEK_CALL_HI16;
116    break;
117  case MipsII::MO_CALL_LO16:
118    TargetKind = MipsMCExpr::MEK_CALL_LO16;
119    break;
120  }
121
122  switch (MOTy) {
123  case MachineOperand::MO_MachineBasicBlock:
124    Symbol = MO.getMBB()->getSymbol();
125    break;
126
127  case MachineOperand::MO_GlobalAddress:
128    Symbol = AsmPrinter.getSymbol(MO.getGlobal());
129    Offset += MO.getOffset();
130    break;
131
132  case MachineOperand::MO_BlockAddress:
133    Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress());
134    Offset += MO.getOffset();
135    break;
136
137  case MachineOperand::MO_ExternalSymbol:
138    Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName());
139    Offset += MO.getOffset();
140    break;
141
142  case MachineOperand::MO_MCSymbol:
143    Symbol = MO.getMCSymbol();
144    Offset += MO.getOffset();
145    break;
146
147  case MachineOperand::MO_JumpTableIndex:
148    Symbol = AsmPrinter.GetJTISymbol(MO.getIndex());
149    break;
150
151  case MachineOperand::MO_ConstantPoolIndex:
152    Symbol = AsmPrinter.GetCPISymbol(MO.getIndex());
153    Offset += MO.getOffset();
154    break;
155
156  default:
157    llvm_unreachable("<unknown operand type>");
158  }
159
160  const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, Kind, *Ctx);
161
162  if (Offset) {
163    // Assume offset is never negative.
164    assert(Offset > 0);
165
166    Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, *Ctx),
167                                   *Ctx);
168  }
169
170  if (IsGpOff)
171    Expr = MipsMCExpr::createGpOff(TargetKind, Expr, *Ctx);
172  else if (TargetKind != MipsMCExpr::MEK_None)
173    Expr = MipsMCExpr::create(TargetKind, Expr, *Ctx);
174
175  return MCOperand::createExpr(Expr);
176}
177
178MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO,
179                                        unsigned offset) const {
180  MachineOperandType MOTy = MO.getType();
181
182  switch (MOTy) {
183  default: llvm_unreachable("unknown operand type");
184  case MachineOperand::MO_Register:
185    // Ignore all implicit register operands.
186    if (MO.isImplicit()) break;
187    return MCOperand::createReg(MO.getReg());
188  case MachineOperand::MO_Immediate:
189    return MCOperand::createImm(MO.getImm() + offset);
190  case MachineOperand::MO_MachineBasicBlock:
191  case MachineOperand::MO_GlobalAddress:
192  case MachineOperand::MO_ExternalSymbol:
193  case MachineOperand::MO_MCSymbol:
194  case MachineOperand::MO_JumpTableIndex:
195  case MachineOperand::MO_ConstantPoolIndex:
196  case MachineOperand::MO_BlockAddress:
197    return LowerSymbolOperand(MO, MOTy, offset);
198  case MachineOperand::MO_RegisterMask:
199    break;
200 }
201
202  return MCOperand();
203}
204
205MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1,
206                                     MachineBasicBlock *BB2,
207                                     MipsMCExpr::MipsExprKind Kind) const {
208  const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::create(BB1->getSymbol(), *Ctx);
209  const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::create(BB2->getSymbol(), *Ctx);
210  const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Sym1, Sym2, *Ctx);
211
212  return MCOperand::createExpr(MipsMCExpr::create(Kind, Sub, *Ctx));
213}
214
215void MipsMCInstLower::
216lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const {
217  OutMI.setOpcode(Mips::LUi);
218
219  // Lower register operand.
220  OutMI.addOperand(LowerOperand(MI->getOperand(0)));
221
222  // Create %hi($tgt-$baltgt).
223  OutMI.addOperand(createSub(MI->getOperand(1).getMBB(),
224                             MI->getOperand(2).getMBB(),
225                             MipsMCExpr::MEK_HI));
226}
227
228void MipsMCInstLower::lowerLongBranchADDiu(
229    const MachineInstr *MI, MCInst &OutMI, int Opcode,
230    MipsMCExpr::MipsExprKind Kind) const {
231  OutMI.setOpcode(Opcode);
232
233  // Lower two register operands.
234  for (unsigned I = 0, E = 2; I != E; ++I) {
235    const MachineOperand &MO = MI->getOperand(I);
236    OutMI.addOperand(LowerOperand(MO));
237  }
238
239  // Create %lo($tgt-$baltgt) or %hi($tgt-$baltgt).
240  OutMI.addOperand(createSub(MI->getOperand(2).getMBB(),
241                             MI->getOperand(3).getMBB(), Kind));
242}
243
244bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI,
245                                      MCInst &OutMI) const {
246  switch (MI->getOpcode()) {
247  default:
248    return false;
249  case Mips::LONG_BRANCH_LUi:
250    lowerLongBranchLUi(MI, OutMI);
251    return true;
252  case Mips::LONG_BRANCH_ADDiu:
253    lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu, MipsMCExpr::MEK_LO);
254    return true;
255  case Mips::LONG_BRANCH_DADDiu:
256    unsigned TargetFlags = MI->getOperand(2).getTargetFlags();
257    if (TargetFlags == MipsII::MO_ABS_HI)
258      lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu, MipsMCExpr::MEK_HI);
259    else if (TargetFlags == MipsII::MO_ABS_LO)
260      lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu, MipsMCExpr::MEK_LO);
261    else
262      report_fatal_error("Unexpected flags for LONG_BRANCH_DADDiu");
263    return true;
264  }
265}
266
267void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
268  if (lowerLongBranch(MI, OutMI))
269    return;
270
271  OutMI.setOpcode(MI->getOpcode());
272
273  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
274    const MachineOperand &MO = MI->getOperand(i);
275    MCOperand MCOp = LowerOperand(MO);
276
277    if (MCOp.isValid())
278      OutMI.addOperand(MCOp);
279  }
280}
281
282