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/MCContext.h"
23 #include "llvm/MC/MCExpr.h"
24 #include "llvm/MC/MCInst.h"
25 #include "llvm/Support/CodeGen.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Target/TargetLoweringObjectFile.h"
28 #include "llvm/Target/TargetMachine.h"
29 using namespace llvm;
30 
31 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
32 
AArch64MCInstLower(MCContext & ctx,AsmPrinter & printer)33 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
34     : Ctx(ctx), Printer(printer) {}
35 
36 MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const37 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
38   const GlobalValue *GV = MO.getGlobal();
39   unsigned TargetFlags = MO.getTargetFlags();
40   const Triple &TheTriple = Printer.TM.getTargetTriple();
41   if (!TheTriple.isOSBinFormatCOFF())
42     return Printer.getSymbol(GV);
43 
44   assert(TheTriple.isOSWindows() &&
45          "Windows is the only supported COFF target");
46 
47   bool IsIndirect = (TargetFlags & AArch64II::MO_DLLIMPORT);
48   if (!IsIndirect)
49     return Printer.getSymbol(GV);
50 
51   SmallString<128> Name;
52   Name = "__imp_";
53   Printer.TM.getNameWithPrefix(Name, GV,
54                                Printer.getObjFileLowering().getMangler());
55 
56   return Ctx.getOrCreateSymbol(Name);
57 }
58 
59 MCSymbol *
GetExternalSymbolSymbol(const MachineOperand & MO) const60 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
61   return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
62 }
63 
lowerSymbolOperandDarwin(const MachineOperand & MO,MCSymbol * Sym) const64 MCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
65                                                        MCSymbol *Sym) const {
66   // FIXME: We would like an efficient form for this, so we don't have to do a
67   // lot of extra uniquing.
68   MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
69   if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
70     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
71       RefKind = MCSymbolRefExpr::VK_GOTPAGE;
72     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
73              AArch64II::MO_PAGEOFF)
74       RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
75     else
76       llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
77   } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
78     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
79       RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
80     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
81              AArch64II::MO_PAGEOFF)
82       RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
83     else
84       llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
85   } else {
86     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
87       RefKind = MCSymbolRefExpr::VK_PAGE;
88     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
89              AArch64II::MO_PAGEOFF)
90       RefKind = MCSymbolRefExpr::VK_PAGEOFF;
91   }
92   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
93   if (!MO.isJTI() && MO.getOffset())
94     Expr = MCBinaryExpr::createAdd(
95         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
96   return MCOperand::createExpr(Expr);
97 }
98 
lowerSymbolOperandELF(const MachineOperand & MO,MCSymbol * Sym) const99 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
100                                                     MCSymbol *Sym) const {
101   uint32_t RefFlags = 0;
102 
103   if (MO.getTargetFlags() & AArch64II::MO_GOT)
104     RefFlags |= AArch64MCExpr::VK_GOT;
105   else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
106     TLSModel::Model Model;
107     if (MO.isGlobal()) {
108       const GlobalValue *GV = MO.getGlobal();
109       Model = Printer.TM.getTLSModel(GV);
110       if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
111           Model == TLSModel::LocalDynamic)
112         Model = TLSModel::GeneralDynamic;
113 
114     } else {
115       assert(MO.isSymbol() &&
116              StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
117              "unexpected external TLS symbol");
118       // The general dynamic access sequence is used to get the
119       // address of _TLS_MODULE_BASE_.
120       Model = TLSModel::GeneralDynamic;
121     }
122     switch (Model) {
123     case TLSModel::InitialExec:
124       RefFlags |= AArch64MCExpr::VK_GOTTPREL;
125       break;
126     case TLSModel::LocalExec:
127       RefFlags |= AArch64MCExpr::VK_TPREL;
128       break;
129     case TLSModel::LocalDynamic:
130       RefFlags |= AArch64MCExpr::VK_DTPREL;
131       break;
132     case TLSModel::GeneralDynamic:
133       RefFlags |= AArch64MCExpr::VK_TLSDESC;
134       break;
135     }
136   } else {
137     // No modifier means this is a generic reference, classified as absolute for
138     // the cases where it matters (:abs_g0: etc).
139     RefFlags |= AArch64MCExpr::VK_ABS;
140   }
141 
142   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
143     RefFlags |= AArch64MCExpr::VK_PAGE;
144   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
145            AArch64II::MO_PAGEOFF)
146     RefFlags |= AArch64MCExpr::VK_PAGEOFF;
147   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
148     RefFlags |= AArch64MCExpr::VK_G3;
149   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
150     RefFlags |= AArch64MCExpr::VK_G2;
151   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
152     RefFlags |= AArch64MCExpr::VK_G1;
153   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
154     RefFlags |= AArch64MCExpr::VK_G0;
155   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
156     RefFlags |= AArch64MCExpr::VK_HI12;
157 
158   if (MO.getTargetFlags() & AArch64II::MO_NC)
159     RefFlags |= AArch64MCExpr::VK_NC;
160 
161   const MCExpr *Expr =
162       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
163   if (!MO.isJTI() && MO.getOffset())
164     Expr = MCBinaryExpr::createAdd(
165         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
166 
167   AArch64MCExpr::VariantKind RefKind;
168   RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
169   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
170 
171   return MCOperand::createExpr(Expr);
172 }
173 
lowerSymbolOperandCOFF(const MachineOperand & MO,MCSymbol * Sym) const174 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
175                                                      MCSymbol *Sym) const {
176   AArch64MCExpr::VariantKind RefKind = AArch64MCExpr::VK_NONE;
177   if (MO.getTargetFlags() & AArch64II::MO_TLS) {
178     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
179       RefKind = AArch64MCExpr::VK_SECREL_LO12;
180     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
181              AArch64II::MO_HI12)
182       RefKind = AArch64MCExpr::VK_SECREL_HI12;
183   }
184   const MCExpr *Expr =
185       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
186   if (!MO.isJTI() && MO.getOffset())
187     Expr = MCBinaryExpr::createAdd(
188         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
189   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
190   return MCOperand::createExpr(Expr);
191 }
192 
LowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const193 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
194                                                  MCSymbol *Sym) const {
195   if (Printer.TM.getTargetTriple().isOSDarwin())
196     return lowerSymbolOperandDarwin(MO, Sym);
197   if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
198     return lowerSymbolOperandCOFF(MO, Sym);
199 
200   assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
201   return lowerSymbolOperandELF(MO, Sym);
202 }
203 
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const204 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
205                                       MCOperand &MCOp) const {
206   switch (MO.getType()) {
207   default:
208     llvm_unreachable("unknown operand type");
209   case MachineOperand::MO_Register:
210     // Ignore all implicit register operands.
211     if (MO.isImplicit())
212       return false;
213     MCOp = MCOperand::createReg(MO.getReg());
214     break;
215   case MachineOperand::MO_RegisterMask:
216     // Regmasks are like implicit defs.
217     return false;
218   case MachineOperand::MO_Immediate:
219     MCOp = MCOperand::createImm(MO.getImm());
220     break;
221   case MachineOperand::MO_MachineBasicBlock:
222     MCOp = MCOperand::createExpr(
223         MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
224     break;
225   case MachineOperand::MO_GlobalAddress:
226     MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
227     break;
228   case MachineOperand::MO_ExternalSymbol:
229     MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
230     break;
231   case MachineOperand::MO_MCSymbol:
232     MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
233     break;
234   case MachineOperand::MO_JumpTableIndex:
235     MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
236     break;
237   case MachineOperand::MO_ConstantPoolIndex:
238     MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
239     break;
240   case MachineOperand::MO_BlockAddress:
241     MCOp = LowerSymbolOperand(
242         MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
243     break;
244   }
245   return true;
246 }
247 
Lower(const MachineInstr * MI,MCInst & OutMI) const248 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
249   OutMI.setOpcode(MI->getOpcode());
250 
251   for (const MachineOperand &MO : MI->operands()) {
252     MCOperand MCOp;
253     if (lowerOperand(MO, MCOp))
254       OutMI.addOperand(MCOp);
255   }
256 }
257