1276479Sdim//==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file contains code to lower AArch64 MachineInstrs to their corresponding
11249259Sdim// MCInst records.
12249259Sdim//
13249259Sdim//===----------------------------------------------------------------------===//
14249259Sdim
15276479Sdim#include "AArch64MCInstLower.h"
16249259Sdim#include "MCTargetDesc/AArch64MCExpr.h"
17249259Sdim#include "Utils/AArch64BaseInfo.h"
18249259Sdim#include "llvm/CodeGen/AsmPrinter.h"
19276479Sdim#include "llvm/CodeGen/MachineBasicBlock.h"
20276479Sdim#include "llvm/CodeGen/MachineInstr.h"
21276479Sdim#include "llvm/IR/Mangler.h"
22249259Sdim#include "llvm/MC/MCExpr.h"
23249259Sdim#include "llvm/MC/MCInst.h"
24276479Sdim#include "llvm/Support/CodeGen.h"
25280865Semaste#include "llvm/Support/CommandLine.h"
26276479Sdim#include "llvm/Target/TargetMachine.h"
27249259Sdimusing namespace llvm;
28249259Sdim
29280865Semasteextern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
30280865Semaste
31280031SdimAArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
32276479Sdim    : Ctx(ctx), Printer(printer), TargetTriple(printer.getTargetTriple()) {}
33249259Sdim
34276479SdimMCSymbol *
35276479SdimAArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
36276479Sdim  return Printer.getSymbol(MO.getGlobal());
37276479Sdim}
38249259Sdim
39276479SdimMCSymbol *
40276479SdimAArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
41276479Sdim  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
42276479Sdim}
43276479Sdim
44276479SdimMCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
45276479Sdim                                                       MCSymbol *Sym) const {
46276479Sdim  // FIXME: We would like an efficient form for this, so we don't have to do a
47276479Sdim  // lot of extra uniquing.
48276479Sdim  MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
49276479Sdim  if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
50276479Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
51276479Sdim      RefKind = MCSymbolRefExpr::VK_GOTPAGE;
52276479Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
53276479Sdim             AArch64II::MO_PAGEOFF)
54276479Sdim      RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
55276479Sdim    else
56276479Sdim      llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
57276479Sdim  } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
58276479Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
59276479Sdim      RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
60276479Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
61276479Sdim             AArch64II::MO_PAGEOFF)
62276479Sdim      RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
63276479Sdim    else
64276479Sdim      llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
65276479Sdim  } else {
66276479Sdim    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
67276479Sdim      RefKind = MCSymbolRefExpr::VK_PAGE;
68276479Sdim    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
69276479Sdim             AArch64II::MO_PAGEOFF)
70276479Sdim      RefKind = MCSymbolRefExpr::VK_PAGEOFF;
71249259Sdim  }
72288943Sdim  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
73276479Sdim  if (!MO.isJTI() && MO.getOffset())
74288943Sdim    Expr = MCBinaryExpr::createAdd(
75288943Sdim        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
76288943Sdim  return MCOperand::createExpr(Expr);
77276479Sdim}
78249259Sdim
79276479SdimMCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
80276479Sdim                                                    MCSymbol *Sym) const {
81276479Sdim  uint32_t RefFlags = 0;
82276479Sdim
83276479Sdim  if (MO.getTargetFlags() & AArch64II::MO_GOT)
84276479Sdim    RefFlags |= AArch64MCExpr::VK_GOT;
85276479Sdim  else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
86276479Sdim    TLSModel::Model Model;
87276479Sdim    if (MO.isGlobal()) {
88276479Sdim      const GlobalValue *GV = MO.getGlobal();
89276479Sdim      Model = Printer.TM.getTLSModel(GV);
90280865Semaste      if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
91280865Semaste          Model == TLSModel::LocalDynamic)
92280865Semaste        Model = TLSModel::GeneralDynamic;
93280865Semaste
94276479Sdim    } else {
95276479Sdim      assert(MO.isSymbol() &&
96276479Sdim             StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
97276479Sdim             "unexpected external TLS symbol");
98280865Semaste      // The general dynamic access sequence is used to get the
99280865Semaste      // address of _TLS_MODULE_BASE_.
100276479Sdim      Model = TLSModel::GeneralDynamic;
101276479Sdim    }
102276479Sdim    switch (Model) {
103276479Sdim    case TLSModel::InitialExec:
104276479Sdim      RefFlags |= AArch64MCExpr::VK_GOTTPREL;
105276479Sdim      break;
106276479Sdim    case TLSModel::LocalExec:
107276479Sdim      RefFlags |= AArch64MCExpr::VK_TPREL;
108276479Sdim      break;
109276479Sdim    case TLSModel::LocalDynamic:
110276479Sdim      RefFlags |= AArch64MCExpr::VK_DTPREL;
111276479Sdim      break;
112276479Sdim    case TLSModel::GeneralDynamic:
113276479Sdim      RefFlags |= AArch64MCExpr::VK_TLSDESC;
114276479Sdim      break;
115276479Sdim    }
116276479Sdim  } else {
117276479Sdim    // No modifier means this is a generic reference, classified as absolute for
118276479Sdim    // the cases where it matters (:abs_g0: etc).
119276479Sdim    RefFlags |= AArch64MCExpr::VK_ABS;
120276479Sdim  }
121276479Sdim
122276479Sdim  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
123276479Sdim    RefFlags |= AArch64MCExpr::VK_PAGE;
124276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
125276479Sdim           AArch64II::MO_PAGEOFF)
126276479Sdim    RefFlags |= AArch64MCExpr::VK_PAGEOFF;
127276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
128276479Sdim    RefFlags |= AArch64MCExpr::VK_G3;
129276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
130276479Sdim    RefFlags |= AArch64MCExpr::VK_G2;
131276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
132276479Sdim    RefFlags |= AArch64MCExpr::VK_G1;
133276479Sdim  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
134276479Sdim    RefFlags |= AArch64MCExpr::VK_G0;
135280865Semaste  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
136280865Semaste    RefFlags |= AArch64MCExpr::VK_HI12;
137276479Sdim
138276479Sdim  if (MO.getTargetFlags() & AArch64II::MO_NC)
139276479Sdim    RefFlags |= AArch64MCExpr::VK_NC;
140276479Sdim
141276479Sdim  const MCExpr *Expr =
142288943Sdim      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
143249259Sdim  if (!MO.isJTI() && MO.getOffset())
144288943Sdim    Expr = MCBinaryExpr::createAdd(
145288943Sdim        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
146249259Sdim
147276479Sdim  AArch64MCExpr::VariantKind RefKind;
148276479Sdim  RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
149288943Sdim  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
150276479Sdim
151288943Sdim  return MCOperand::createExpr(Expr);
152249259Sdim}
153249259Sdim
154276479SdimMCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
155276479Sdim                                                 MCSymbol *Sym) const {
156276479Sdim  if (TargetTriple.isOSDarwin())
157276479Sdim    return lowerSymbolOperandDarwin(MO, Sym);
158276479Sdim
159276479Sdim  assert(TargetTriple.isOSBinFormatELF() && "Expect Darwin or ELF target");
160276479Sdim  return lowerSymbolOperandELF(MO, Sym);
161276479Sdim}
162276479Sdim
163276479Sdimbool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
164276479Sdim                                      MCOperand &MCOp) const {
165249259Sdim  switch (MO.getType()) {
166276479Sdim  default:
167276479Sdim    llvm_unreachable("unknown operand type");
168249259Sdim  case MachineOperand::MO_Register:
169276479Sdim    // Ignore all implicit register operands.
170249259Sdim    if (MO.isImplicit())
171249259Sdim      return false;
172288943Sdim    MCOp = MCOperand::createReg(MO.getReg());
173249259Sdim    break;
174276479Sdim  case MachineOperand::MO_RegisterMask:
175276479Sdim    // Regmasks are like implicit defs.
176276479Sdim    return false;
177249259Sdim  case MachineOperand::MO_Immediate:
178288943Sdim    MCOp = MCOperand::createImm(MO.getImm());
179249259Sdim    break;
180276479Sdim  case MachineOperand::MO_MachineBasicBlock:
181288943Sdim    MCOp = MCOperand::createExpr(
182288943Sdim        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
183261991Sdim    break;
184276479Sdim  case MachineOperand::MO_GlobalAddress:
185276479Sdim    MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
186249259Sdim    break;
187249259Sdim  case MachineOperand::MO_ExternalSymbol:
188276479Sdim    MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
189249259Sdim    break;
190288943Sdim  case MachineOperand::MO_MCSymbol:
191288943Sdim    MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
192288943Sdim    break;
193249259Sdim  case MachineOperand::MO_JumpTableIndex:
194276479Sdim    MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
195249259Sdim    break;
196249259Sdim  case MachineOperand::MO_ConstantPoolIndex:
197276479Sdim    MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
198249259Sdim    break;
199276479Sdim  case MachineOperand::MO_BlockAddress:
200276479Sdim    MCOp = LowerSymbolOperand(
201276479Sdim        MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
202276479Sdim    break;
203249259Sdim  }
204249259Sdim  return true;
205249259Sdim}
206249259Sdim
207276479Sdimvoid AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
208249259Sdim  OutMI.setOpcode(MI->getOpcode());
209249259Sdim
210296417Sdim  for (const MachineOperand &MO : MI->operands()) {
211249259Sdim    MCOperand MCOp;
212296417Sdim    if (lowerOperand(MO, MCOp))
213249259Sdim      OutMI.addOperand(MCOp);
214249259Sdim  }
215249259Sdim}
216