1//==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an 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 AArch64 MachineInstrs to their corresponding
11// MCInst records.
12//
13//===----------------------------------------------------------------------===//
14
15#include "AArch64MCInstLower.h"
16#include "MCTargetDesc/AArch64MCExpr.h"
17#include "Utils/AArch64BaseInfo.h"
18#include "llvm/CodeGen/AsmPrinter.h"
19#include "llvm/CodeGen/MachineBasicBlock.h"
20#include "llvm/CodeGen/MachineInstr.h"
21#include "llvm/IR/Mangler.h"
22#include "llvm/MC/MCExpr.h"
23#include "llvm/MC/MCInst.h"
24#include "llvm/Support/CodeGen.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Target/TargetMachine.h"
27using namespace llvm;
28
29extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
30
31AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
32    : Ctx(ctx), Printer(printer), TargetTriple(printer.getTargetTriple()) {}
33
34MCSymbol *
35AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
36  return Printer.getSymbol(MO.getGlobal());
37}
38
39MCSymbol *
40AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
41  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
42}
43
44MCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
45                                                       MCSymbol *Sym) const {
46  // FIXME: We would like an efficient form for this, so we don't have to do a
47  // lot of extra uniquing.
48  MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
49  if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
50    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
51      RefKind = MCSymbolRefExpr::VK_GOTPAGE;
52    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
53             AArch64II::MO_PAGEOFF)
54      RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
55    else
56      llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
57  } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
58    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
59      RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
60    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
61             AArch64II::MO_PAGEOFF)
62      RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
63    else
64      llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
65  } else {
66    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
67      RefKind = MCSymbolRefExpr::VK_PAGE;
68    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
69             AArch64II::MO_PAGEOFF)
70      RefKind = MCSymbolRefExpr::VK_PAGEOFF;
71  }
72  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
73  if (!MO.isJTI() && MO.getOffset())
74    Expr = MCBinaryExpr::createAdd(
75        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
76  return MCOperand::createExpr(Expr);
77}
78
79MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
80                                                    MCSymbol *Sym) const {
81  uint32_t RefFlags = 0;
82
83  if (MO.getTargetFlags() & AArch64II::MO_GOT)
84    RefFlags |= AArch64MCExpr::VK_GOT;
85  else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
86    TLSModel::Model Model;
87    if (MO.isGlobal()) {
88      const GlobalValue *GV = MO.getGlobal();
89      Model = Printer.TM.getTLSModel(GV);
90      if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
91          Model == TLSModel::LocalDynamic)
92        Model = TLSModel::GeneralDynamic;
93
94    } else {
95      assert(MO.isSymbol() &&
96             StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
97             "unexpected external TLS symbol");
98      // The general dynamic access sequence is used to get the
99      // address of _TLS_MODULE_BASE_.
100      Model = TLSModel::GeneralDynamic;
101    }
102    switch (Model) {
103    case TLSModel::InitialExec:
104      RefFlags |= AArch64MCExpr::VK_GOTTPREL;
105      break;
106    case TLSModel::LocalExec:
107      RefFlags |= AArch64MCExpr::VK_TPREL;
108      break;
109    case TLSModel::LocalDynamic:
110      RefFlags |= AArch64MCExpr::VK_DTPREL;
111      break;
112    case TLSModel::GeneralDynamic:
113      RefFlags |= AArch64MCExpr::VK_TLSDESC;
114      break;
115    }
116  } else {
117    // No modifier means this is a generic reference, classified as absolute for
118    // the cases where it matters (:abs_g0: etc).
119    RefFlags |= AArch64MCExpr::VK_ABS;
120  }
121
122  if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
123    RefFlags |= AArch64MCExpr::VK_PAGE;
124  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
125           AArch64II::MO_PAGEOFF)
126    RefFlags |= AArch64MCExpr::VK_PAGEOFF;
127  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
128    RefFlags |= AArch64MCExpr::VK_G3;
129  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
130    RefFlags |= AArch64MCExpr::VK_G2;
131  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
132    RefFlags |= AArch64MCExpr::VK_G1;
133  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
134    RefFlags |= AArch64MCExpr::VK_G0;
135  else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
136    RefFlags |= AArch64MCExpr::VK_HI12;
137
138  if (MO.getTargetFlags() & AArch64II::MO_NC)
139    RefFlags |= AArch64MCExpr::VK_NC;
140
141  const MCExpr *Expr =
142      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
143  if (!MO.isJTI() && MO.getOffset())
144    Expr = MCBinaryExpr::createAdd(
145        Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
146
147  AArch64MCExpr::VariantKind RefKind;
148  RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
149  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
150
151  return MCOperand::createExpr(Expr);
152}
153
154MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
155                                                 MCSymbol *Sym) const {
156  if (TargetTriple.isOSDarwin())
157    return lowerSymbolOperandDarwin(MO, Sym);
158
159  assert(TargetTriple.isOSBinFormatELF() && "Expect Darwin or ELF target");
160  return lowerSymbolOperandELF(MO, Sym);
161}
162
163bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
164                                      MCOperand &MCOp) const {
165  switch (MO.getType()) {
166  default:
167    llvm_unreachable("unknown operand type");
168  case MachineOperand::MO_Register:
169    // Ignore all implicit register operands.
170    if (MO.isImplicit())
171      return false;
172    MCOp = MCOperand::createReg(MO.getReg());
173    break;
174  case MachineOperand::MO_RegisterMask:
175    // Regmasks are like implicit defs.
176    return false;
177  case MachineOperand::MO_Immediate:
178    MCOp = MCOperand::createImm(MO.getImm());
179    break;
180  case MachineOperand::MO_MachineBasicBlock:
181    MCOp = MCOperand::createExpr(
182        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
183    break;
184  case MachineOperand::MO_GlobalAddress:
185    MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
186    break;
187  case MachineOperand::MO_ExternalSymbol:
188    MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
189    break;
190  case MachineOperand::MO_MCSymbol:
191    MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
192    break;
193  case MachineOperand::MO_JumpTableIndex:
194    MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
195    break;
196  case MachineOperand::MO_ConstantPoolIndex:
197    MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
198    break;
199  case MachineOperand::MO_BlockAddress:
200    MCOp = LowerSymbolOperand(
201        MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
202    break;
203  }
204  return true;
205}
206
207void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
208  OutMI.setOpcode(MI->getOpcode());
209
210  for (const MachineOperand &MO : MI->operands()) {
211    MCOperand MCOp;
212    if (lowerOperand(MO, MCOp))
213      OutMI.addOperand(MCOp);
214  }
215}
216