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