1//==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an 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 AArch64 MachineInstrs to their corresponding
10// MCInst records.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AArch64MCInstLower.h"
15#include "MCTargetDesc/AArch64MCExpr.h"
16#include "Utils/AArch64BaseInfo.h"
17#include "llvm/CodeGen/AsmPrinter.h"
18#include "llvm/CodeGen/MachineBasicBlock.h"
19#include "llvm/CodeGen/MachineInstr.h"
20#include "llvm/CodeGen/MachineModuleInfoImpls.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/Support/CodeGen.h"
26#include "llvm/Support/CommandLine.h"
27#include "llvm/Target/TargetLoweringObjectFile.h"
28#include "llvm/Target/TargetMachine.h"
29using namespace llvm;
30
31extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
32
33AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
34    : Ctx(ctx), Printer(printer) {}
35
36MCSymbol *
37AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
38  const GlobalValue *GV = MO.getGlobal();
39  unsigned TargetFlags = MO.getTargetFlags();
40  const Triple &TheTriple = Printer.TM.getTargetTriple();
41  if (!TheTriple.isOSBinFormatCOFF())
42    return Printer.getSymbol(GV);
43
44  assert(TheTriple.isOSWindows() &&
45         "Windows is the only supported COFF target");
46
47  bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
48  if (!IsIndirect)
49    return Printer.getSymbol(GV);
50
51  SmallString<128> Name;
52  if (TargetFlags & AArch64II::MO_DLLIMPORT)
53    Name = "__imp_";
54  else if (TargetFlags & AArch64II::MO_COFFSTUB)
55    Name = ".refptr.";
56  Printer.TM.getNameWithPrefix(Name, GV,
57                               Printer.getObjFileLowering().getMangler());
58
59  MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
60
61  if (TargetFlags & AArch64II::MO_COFFSTUB) {
62    MachineModuleInfoCOFF &MMICOFF =
63        Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
64    MachineModuleInfoImpl::StubValueTy &StubSym =
65        MMICOFF.getGVStubEntry(MCSym);
66
67    if (!StubSym.getPointer())
68      StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
69  }
70
71  return MCSym;
72}
73
74MCSymbol *
75AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
76  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
77}
78
79MCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
80                                                       MCSymbol *Sym) const {
81  // FIXME: We would like an efficient form for this, so we don't have to do a
82  // lot of extra uniquing.
83  MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
84  if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
85    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
86      RefKind = MCSymbolRefExpr::VK_GOTPAGE;
87    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
88             AArch64II::MO_PAGEOFF)
89      RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
90    else
91      llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
92  } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
93    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
94      RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
95    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
96             AArch64II::MO_PAGEOFF)
97      RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
98    else
99      llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
100  } else {
101    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
102      RefKind = MCSymbolRefExpr::VK_PAGE;
103    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
104             AArch64II::MO_PAGEOFF)
105      RefKind = MCSymbolRefExpr::VK_PAGEOFF;
106  }
107  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
108  if (!MO.isJTI() && MO.getOffset())
109    Expr = MCBinaryExpr::createAdd(
110        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
111  return MCOperand::createExpr(Expr);
112}
113
114MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
115                                                    MCSymbol *Sym) const {
116  uint32_t RefFlags = 0;
117
118  if (MO.getTargetFlags() & AArch64II::MO_GOT)
119    RefFlags |= AArch64MCExpr::VK_GOT;
120  else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
121    TLSModel::Model Model;
122    if (MO.isGlobal()) {
123      const GlobalValue *GV = MO.getGlobal();
124      Model = Printer.TM.getTLSModel(GV);
125      if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
126          Model == TLSModel::LocalDynamic)
127        Model = TLSModel::GeneralDynamic;
128
129    } else {
130      assert(MO.isSymbol() &&
131             StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
132             "unexpected external TLS symbol");
133      // The general dynamic access sequence is used to get the
134      // address of _TLS_MODULE_BASE_.
135      Model = TLSModel::GeneralDynamic;
136    }
137    switch (Model) {
138    case TLSModel::InitialExec:
139      RefFlags |= AArch64MCExpr::VK_GOTTPREL;
140      break;
141    case TLSModel::LocalExec:
142      RefFlags |= AArch64MCExpr::VK_TPREL;
143      break;
144    case TLSModel::LocalDynamic:
145      RefFlags |= AArch64MCExpr::VK_DTPREL;
146      break;
147    case TLSModel::GeneralDynamic:
148      RefFlags |= AArch64MCExpr::VK_TLSDESC;
149      break;
150    }
151  } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
152    RefFlags |= AArch64MCExpr::VK_PREL;
153  } else {
154    // No modifier means this is a generic reference, classified as absolute for
155    // the cases where it matters (:abs_g0: etc).
156    RefFlags |= AArch64MCExpr::VK_ABS;
157  }
158
159  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
160    RefFlags |= AArch64MCExpr::VK_PAGE;
161  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
162           AArch64II::MO_PAGEOFF)
163    RefFlags |= AArch64MCExpr::VK_PAGEOFF;
164  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
165    RefFlags |= AArch64MCExpr::VK_G3;
166  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
167    RefFlags |= AArch64MCExpr::VK_G2;
168  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
169    RefFlags |= AArch64MCExpr::VK_G1;
170  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
171    RefFlags |= AArch64MCExpr::VK_G0;
172  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
173    RefFlags |= AArch64MCExpr::VK_HI12;
174
175  if (MO.getTargetFlags() & AArch64II::MO_NC)
176    RefFlags |= AArch64MCExpr::VK_NC;
177
178  const MCExpr *Expr =
179      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
180  if (!MO.isJTI() && MO.getOffset())
181    Expr = MCBinaryExpr::createAdd(
182        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
183
184  AArch64MCExpr::VariantKind RefKind;
185  RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
186  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
187
188  return MCOperand::createExpr(Expr);
189}
190
191MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
192                                                     MCSymbol *Sym) const {
193  uint32_t RefFlags = 0;
194
195  if (MO.getTargetFlags() & AArch64II::MO_TLS) {
196    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
197      RefFlags |= AArch64MCExpr::VK_SECREL_LO12;
198    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
199             AArch64II::MO_HI12)
200      RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
201
202  } else if (MO.getTargetFlags() & AArch64II::MO_S) {
203    RefFlags |= AArch64MCExpr::VK_SABS;
204  } else {
205    RefFlags |= AArch64MCExpr::VK_ABS;
206  }
207
208  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
209    RefFlags |= AArch64MCExpr::VK_G3;
210  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
211    RefFlags |= AArch64MCExpr::VK_G2;
212  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
213    RefFlags |= AArch64MCExpr::VK_G1;
214  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
215    RefFlags |= AArch64MCExpr::VK_G0;
216
217  // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
218  // because setting VK_NC for others would mean setting their respective
219  // RefFlags correctly.  We should do this in a separate patch.
220  if (MO.getTargetFlags() & AArch64II::MO_NC) {
221    auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
222    if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
223        MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
224      RefFlags |= AArch64MCExpr::VK_NC;
225  }
226
227  const MCExpr *Expr =
228      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
229  if (!MO.isJTI() && MO.getOffset())
230    Expr = MCBinaryExpr::createAdd(
231        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
232
233  auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
234  assert(RefKind != AArch64MCExpr::VK_INVALID &&
235         "Invalid relocation requested");
236  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
237
238  return MCOperand::createExpr(Expr);
239}
240
241MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
242                                                 MCSymbol *Sym) const {
243  if (Printer.TM.getTargetTriple().isOSDarwin())
244    return lowerSymbolOperandDarwin(MO, Sym);
245  if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
246    return lowerSymbolOperandCOFF(MO, Sym);
247
248  assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
249  return lowerSymbolOperandELF(MO, Sym);
250}
251
252bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
253                                      MCOperand &MCOp) const {
254  switch (MO.getType()) {
255  default:
256    llvm_unreachable("unknown operand type");
257  case MachineOperand::MO_Register:
258    // Ignore all implicit register operands.
259    if (MO.isImplicit())
260      return false;
261    MCOp = MCOperand::createReg(MO.getReg());
262    break;
263  case MachineOperand::MO_RegisterMask:
264    // Regmasks are like implicit defs.
265    return false;
266  case MachineOperand::MO_Immediate:
267    MCOp = MCOperand::createImm(MO.getImm());
268    break;
269  case MachineOperand::MO_MachineBasicBlock:
270    MCOp = MCOperand::createExpr(
271        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
272    break;
273  case MachineOperand::MO_GlobalAddress:
274    MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
275    break;
276  case MachineOperand::MO_ExternalSymbol:
277    MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
278    break;
279  case MachineOperand::MO_MCSymbol:
280    MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
281    break;
282  case MachineOperand::MO_JumpTableIndex:
283    MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
284    break;
285  case MachineOperand::MO_ConstantPoolIndex:
286    MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
287    break;
288  case MachineOperand::MO_BlockAddress:
289    MCOp = LowerSymbolOperand(
290        MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
291    break;
292  }
293  return true;
294}
295
296void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
297  OutMI.setOpcode(MI->getOpcode());
298
299  for (const MachineOperand &MO : MI->operands()) {
300    MCOperand MCOp;
301    if (lowerOperand(MO, MCOp))
302      OutMI.addOperand(MCOp);
303  }
304
305  switch (OutMI.getOpcode()) {
306  case AArch64::CATCHRET:
307    OutMI = MCInst();
308    OutMI.setOpcode(AArch64::RET);
309    OutMI.addOperand(MCOperand::createReg(AArch64::LR));
310    break;
311  case AArch64::CLEANUPRET:
312    OutMI = MCInst();
313    OutMI.setOpcode(AArch64::RET);
314    OutMI.addOperand(MCOperand::createReg(AArch64::LR));
315    break;
316  }
317}
318