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