1276479Sdim//==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
2249259Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6249259Sdim//
7249259Sdim//===----------------------------------------------------------------------===//
8249259Sdim//
9249259Sdim// This file contains code to lower AArch64 MachineInstrs to their corresponding
10249259Sdim// MCInst records.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14276479Sdim#include "AArch64MCInstLower.h"
15249259Sdim#include "MCTargetDesc/AArch64MCExpr.h"
16249259Sdim#include "Utils/AArch64BaseInfo.h"
17249259Sdim#include "llvm/CodeGen/AsmPrinter.h"
18276479Sdim#include "llvm/CodeGen/MachineBasicBlock.h"
19276479Sdim#include "llvm/CodeGen/MachineInstr.h"
20344779Sdim#include "llvm/CodeGen/MachineModuleInfoImpls.h"
21276479Sdim#include "llvm/IR/Mangler.h"
22327952Sdim#include "llvm/MC/MCContext.h"
23249259Sdim#include "llvm/MC/MCExpr.h"
24249259Sdim#include "llvm/MC/MCInst.h"
25276479Sdim#include "llvm/Support/CodeGen.h"
26280865Semaste#include "llvm/Support/CommandLine.h"
27341825Sdim#include "llvm/Target/TargetLoweringObjectFile.h"
28276479Sdim#include "llvm/Target/TargetMachine.h"
29249259Sdimusing namespace llvm;
30249259Sdim
31280865Semasteextern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
32280865Semaste
33280031SdimAArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
34314564Sdim    : Ctx(ctx), Printer(printer) {}
35249259Sdim
36276479SdimMCSymbol *
37276479SdimAArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
38327952Sdim  const GlobalValue *GV = MO.getGlobal();
39327952Sdim  unsigned TargetFlags = MO.getTargetFlags();
40327952Sdim  const Triple &TheTriple = Printer.TM.getTargetTriple();
41327952Sdim  if (!TheTriple.isOSBinFormatCOFF())
42327952Sdim    return Printer.getSymbol(GV);
43327952Sdim
44327952Sdim  assert(TheTriple.isOSWindows() &&
45327952Sdim         "Windows is the only supported COFF target");
46327952Sdim
47344779Sdim  bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
48327952Sdim  if (!IsIndirect)
49327952Sdim    return Printer.getSymbol(GV);
50327952Sdim
51327952Sdim  SmallString<128> Name;
52344779Sdim  if (TargetFlags & AArch64II::MO_DLLIMPORT)
53344779Sdim    Name = "__imp_";
54344779Sdim  else if (TargetFlags & AArch64II::MO_COFFSTUB)
55344779Sdim    Name = ".refptr.";
56327952Sdim  Printer.TM.getNameWithPrefix(Name, GV,
57327952Sdim                               Printer.getObjFileLowering().getMangler());
58327952Sdim
59344779Sdim  MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
60344779Sdim
61344779Sdim  if (TargetFlags & AArch64II::MO_COFFSTUB) {
62344779Sdim    MachineModuleInfoCOFF &MMICOFF =
63344779Sdim        Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
64344779Sdim    MachineModuleInfoImpl::StubValueTy &StubSym =
65344779Sdim        MMICOFF.getGVStubEntry(MCSym);
66344779Sdim
67344779Sdim    if (!StubSym.getPointer())
68344779Sdim      StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
69344779Sdim  }
70344779Sdim
71344779Sdim  return MCSym;
72276479Sdim}
73249259Sdim
74276479SdimMCSymbol *
75276479SdimAArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
76276479Sdim  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
77276479Sdim}
78276479Sdim
79276479SdimMCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
80276479Sdim                                                       MCSymbol *Sym) const {
81276479Sdim  // FIXME: We would like an efficient form for this, so we don't have to do a
82276479Sdim  // lot of extra uniquing.
83276479Sdim  MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
84276479Sdim  if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
85276479Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
86276479Sdim      RefKind = MCSymbolRefExpr::VK_GOTPAGE;
87276479Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
88276479Sdim             AArch64II::MO_PAGEOFF)
89276479Sdim      RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
90276479Sdim    else
91276479Sdim      llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
92276479Sdim  } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
93276479Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
94276479Sdim      RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
95276479Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
96276479Sdim             AArch64II::MO_PAGEOFF)
97276479Sdim      RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
98276479Sdim    else
99276479Sdim      llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
100276479Sdim  } else {
101276479Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
102276479Sdim      RefKind = MCSymbolRefExpr::VK_PAGE;
103276479Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
104276479Sdim             AArch64II::MO_PAGEOFF)
105276479Sdim      RefKind = MCSymbolRefExpr::VK_PAGEOFF;
106249259Sdim  }
107288943Sdim  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
108276479Sdim  if (!MO.isJTI() && MO.getOffset())
109288943Sdim    Expr = MCBinaryExpr::createAdd(
110288943Sdim        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
111288943Sdim  return MCOperand::createExpr(Expr);
112276479Sdim}
113249259Sdim
114276479SdimMCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
115276479Sdim                                                    MCSymbol *Sym) const {
116276479Sdim  uint32_t RefFlags = 0;
117276479Sdim
118276479Sdim  if (MO.getTargetFlags() & AArch64II::MO_GOT)
119276479Sdim    RefFlags |= AArch64MCExpr::VK_GOT;
120276479Sdim  else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
121276479Sdim    TLSModel::Model Model;
122276479Sdim    if (MO.isGlobal()) {
123276479Sdim      const GlobalValue *GV = MO.getGlobal();
124276479Sdim      Model = Printer.TM.getTLSModel(GV);
125280865Semaste      if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
126280865Semaste          Model == TLSModel::LocalDynamic)
127280865Semaste        Model = TLSModel::GeneralDynamic;
128280865Semaste
129276479Sdim    } else {
130276479Sdim      assert(MO.isSymbol() &&
131276479Sdim             StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
132276479Sdim             "unexpected external TLS symbol");
133280865Semaste      // The general dynamic access sequence is used to get the
134280865Semaste      // address of _TLS_MODULE_BASE_.
135276479Sdim      Model = TLSModel::GeneralDynamic;
136276479Sdim    }
137276479Sdim    switch (Model) {
138276479Sdim    case TLSModel::InitialExec:
139276479Sdim      RefFlags |= AArch64MCExpr::VK_GOTTPREL;
140276479Sdim      break;
141276479Sdim    case TLSModel::LocalExec:
142276479Sdim      RefFlags |= AArch64MCExpr::VK_TPREL;
143276479Sdim      break;
144276479Sdim    case TLSModel::LocalDynamic:
145276479Sdim      RefFlags |= AArch64MCExpr::VK_DTPREL;
146276479Sdim      break;
147276479Sdim    case TLSModel::GeneralDynamic:
148276479Sdim      RefFlags |= AArch64MCExpr::VK_TLSDESC;
149276479Sdim      break;
150276479Sdim    }
151360784Sdim  } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
152360784Sdim    RefFlags |= AArch64MCExpr::VK_PREL;
153276479Sdim  } else {
154276479Sdim    // No modifier means this is a generic reference, classified as absolute for
155276479Sdim    // the cases where it matters (:abs_g0: etc).
156276479Sdim    RefFlags |= AArch64MCExpr::VK_ABS;
157276479Sdim  }
158276479Sdim
159276479Sdim  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
160276479Sdim    RefFlags |= AArch64MCExpr::VK_PAGE;
161276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
162276479Sdim           AArch64II::MO_PAGEOFF)
163276479Sdim    RefFlags |= AArch64MCExpr::VK_PAGEOFF;
164276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
165276479Sdim    RefFlags |= AArch64MCExpr::VK_G3;
166276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
167276479Sdim    RefFlags |= AArch64MCExpr::VK_G2;
168276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
169276479Sdim    RefFlags |= AArch64MCExpr::VK_G1;
170276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
171276479Sdim    RefFlags |= AArch64MCExpr::VK_G0;
172280865Semaste  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
173280865Semaste    RefFlags |= AArch64MCExpr::VK_HI12;
174276479Sdim
175276479Sdim  if (MO.getTargetFlags() & AArch64II::MO_NC)
176276479Sdim    RefFlags |= AArch64MCExpr::VK_NC;
177276479Sdim
178276479Sdim  const MCExpr *Expr =
179288943Sdim      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
180249259Sdim  if (!MO.isJTI() && MO.getOffset())
181288943Sdim    Expr = MCBinaryExpr::createAdd(
182288943Sdim        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
183249259Sdim
184276479Sdim  AArch64MCExpr::VariantKind RefKind;
185276479Sdim  RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
186288943Sdim  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
187276479Sdim
188288943Sdim  return MCOperand::createExpr(Expr);
189249259Sdim}
190249259Sdim
191321369SdimMCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
192321369Sdim                                                     MCSymbol *Sym) const {
193344779Sdim  uint32_t RefFlags = 0;
194344779Sdim
195341825Sdim  if (MO.getTargetFlags() & AArch64II::MO_TLS) {
196341825Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
197344779Sdim      RefFlags |= AArch64MCExpr::VK_SECREL_LO12;
198341825Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
199341825Sdim             AArch64II::MO_HI12)
200344779Sdim      RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
201344779Sdim
202344779Sdim  } else if (MO.getTargetFlags() & AArch64II::MO_S) {
203344779Sdim    RefFlags |= AArch64MCExpr::VK_SABS;
204344779Sdim  } else {
205344779Sdim    RefFlags |= AArch64MCExpr::VK_ABS;
206341825Sdim  }
207344779Sdim
208344779Sdim  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
209344779Sdim    RefFlags |= AArch64MCExpr::VK_G3;
210344779Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
211344779Sdim    RefFlags |= AArch64MCExpr::VK_G2;
212344779Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
213344779Sdim    RefFlags |= AArch64MCExpr::VK_G1;
214344779Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
215344779Sdim    RefFlags |= AArch64MCExpr::VK_G0;
216344779Sdim
217344779Sdim  // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
218344779Sdim  // because setting VK_NC for others would mean setting their respective
219344779Sdim  // RefFlags correctly.  We should do this in a separate patch.
220344779Sdim  if (MO.getTargetFlags() & AArch64II::MO_NC) {
221344779Sdim    auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
222344779Sdim    if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
223344779Sdim        MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
224344779Sdim      RefFlags |= AArch64MCExpr::VK_NC;
225344779Sdim  }
226344779Sdim
227341825Sdim  const MCExpr *Expr =
228341825Sdim      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
229321369Sdim  if (!MO.isJTI() && MO.getOffset())
230321369Sdim    Expr = MCBinaryExpr::createAdd(
231321369Sdim        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
232344779Sdim
233344779Sdim  auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
234344779Sdim  assert(RefKind != AArch64MCExpr::VK_INVALID &&
235344779Sdim         "Invalid relocation requested");
236341825Sdim  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
237344779Sdim
238321369Sdim  return MCOperand::createExpr(Expr);
239321369Sdim}
240321369Sdim
241276479SdimMCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
242276479Sdim                                                 MCSymbol *Sym) const {
243314564Sdim  if (Printer.TM.getTargetTriple().isOSDarwin())
244276479Sdim    return lowerSymbolOperandDarwin(MO, Sym);
245321369Sdim  if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
246321369Sdim    return lowerSymbolOperandCOFF(MO, Sym);
247276479Sdim
248321369Sdim  assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
249276479Sdim  return lowerSymbolOperandELF(MO, Sym);
250276479Sdim}
251276479Sdim
252276479Sdimbool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
253276479Sdim                                      MCOperand &MCOp) const {
254249259Sdim  switch (MO.getType()) {
255276479Sdim  default:
256276479Sdim    llvm_unreachable("unknown operand type");
257249259Sdim  case MachineOperand::MO_Register:
258276479Sdim    // Ignore all implicit register operands.
259249259Sdim    if (MO.isImplicit())
260249259Sdim      return false;
261288943Sdim    MCOp = MCOperand::createReg(MO.getReg());
262249259Sdim    break;
263276479Sdim  case MachineOperand::MO_RegisterMask:
264276479Sdim    // Regmasks are like implicit defs.
265276479Sdim    return false;
266249259Sdim  case MachineOperand::MO_Immediate:
267288943Sdim    MCOp = MCOperand::createImm(MO.getImm());
268249259Sdim    break;
269276479Sdim  case MachineOperand::MO_MachineBasicBlock:
270288943Sdim    MCOp = MCOperand::createExpr(
271288943Sdim        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
272261991Sdim    break;
273276479Sdim  case MachineOperand::MO_GlobalAddress:
274276479Sdim    MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
275249259Sdim    break;
276249259Sdim  case MachineOperand::MO_ExternalSymbol:
277276479Sdim    MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
278249259Sdim    break;
279288943Sdim  case MachineOperand::MO_MCSymbol:
280288943Sdim    MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
281288943Sdim    break;
282249259Sdim  case MachineOperand::MO_JumpTableIndex:
283276479Sdim    MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
284249259Sdim    break;
285249259Sdim  case MachineOperand::MO_ConstantPoolIndex:
286276479Sdim    MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
287249259Sdim    break;
288276479Sdim  case MachineOperand::MO_BlockAddress:
289276479Sdim    MCOp = LowerSymbolOperand(
290276479Sdim        MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
291276479Sdim    break;
292249259Sdim  }
293249259Sdim  return true;
294249259Sdim}
295249259Sdim
296276479Sdimvoid AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
297249259Sdim  OutMI.setOpcode(MI->getOpcode());
298249259Sdim
299296417Sdim  for (const MachineOperand &MO : MI->operands()) {
300249259Sdim    MCOperand MCOp;
301296417Sdim    if (lowerOperand(MO, MCOp))
302249259Sdim      OutMI.addOperand(MCOp);
303249259Sdim  }
304344779Sdim
305344779Sdim  switch (OutMI.getOpcode()) {
306344779Sdim  case AArch64::CATCHRET:
307344779Sdim    OutMI = MCInst();
308344779Sdim    OutMI.setOpcode(AArch64::RET);
309344779Sdim    OutMI.addOperand(MCOperand::createReg(AArch64::LR));
310344779Sdim    break;
311344779Sdim  case AArch64::CLEANUPRET:
312344779Sdim    OutMI = MCInst();
313344779Sdim    OutMI.setOpcode(AArch64::RET);
314344779Sdim    OutMI.addOperand(MCOperand::createReg(AArch64::LR));
315344779Sdim    break;
316344779Sdim  }
317249259Sdim}
318