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