1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains code to lower AArch64 MachineInstrs to their corresponding
10 // MCInst records.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "AArch64MCInstLower.h"
15 #include "MCTargetDesc/AArch64MCExpr.h"
16 #include "Utils/AArch64BaseInfo.h"
17 #include "llvm/CodeGen/AsmPrinter.h"
18 #include "llvm/CodeGen/MachineBasicBlock.h"
19 #include "llvm/CodeGen/MachineInstr.h"
20 #include "llvm/CodeGen/MachineModuleInfoImpls.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/MC/MCStreamer.h"
26 #include "llvm/Support/CodeGen.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Target/TargetLoweringObjectFile.h"
29 #include "llvm/Target/TargetMachine.h"
30 using namespace llvm;
31
32 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
33
AArch64MCInstLower(MCContext & ctx,AsmPrinter & printer)34 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
35 : Ctx(ctx), Printer(printer) {}
36
37 MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const38 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
39 const GlobalValue *GV = MO.getGlobal();
40 unsigned TargetFlags = MO.getTargetFlags();
41 const Triple &TheTriple = Printer.TM.getTargetTriple();
42 if (!TheTriple.isOSBinFormatCOFF())
43 return Printer.getSymbolPreferLocal(*GV);
44
45 assert(TheTriple.isOSWindows() &&
46 "Windows is the only supported COFF target");
47
48 bool IsIndirect =
49 (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_DLLIMPORTAUX |
50 AArch64II::MO_COFFSTUB));
51 if (!IsIndirect)
52 return Printer.getSymbol(GV);
53
54 SmallString<128> Name;
55
56 if (TargetFlags & AArch64II::MO_DLLIMPORTAUX) {
57 // __imp_aux is specific to arm64EC; it represents the actual address of
58 // an imported function without any thunks.
59 //
60 // If we see a reference to an "aux" symbol, also emit a reference to the
61 // corresponding non-aux symbol. Otherwise, the Microsoft linker behaves
62 // strangely when linking against x64 import libararies.
63 //
64 // emitSymbolAttribute() doesn't have any real effect here; it just
65 // ensures the symbol name appears in the assembly without any
66 // side-effects. It might make sense to design a cleaner way to express
67 // this.
68 Name = "__imp_";
69 Printer.TM.getNameWithPrefix(Name, GV,
70 Printer.getObjFileLowering().getMangler());
71 MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);
72 Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);
73
74 Name = "__imp_aux_";
75 } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {
76 Name = "__imp_";
77 } else if (TargetFlags & AArch64II::MO_COFFSTUB) {
78 Name = ".refptr.";
79 }
80 Printer.TM.getNameWithPrefix(Name, GV,
81 Printer.getObjFileLowering().getMangler());
82
83 MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
84
85 if (TargetFlags & AArch64II::MO_COFFSTUB) {
86 MachineModuleInfoCOFF &MMICOFF =
87 Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
88 MachineModuleInfoImpl::StubValueTy &StubSym =
89 MMICOFF.getGVStubEntry(MCSym);
90
91 if (!StubSym.getPointer())
92 StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
93 }
94
95 return MCSym;
96 }
97
98 MCSymbol *
GetExternalSymbolSymbol(const MachineOperand & MO) const99 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
100 return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
101 }
102
lowerSymbolOperandDarwin(const MachineOperand & MO,MCSymbol * Sym) const103 MCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
104 MCSymbol *Sym) const {
105 // FIXME: We would like an efficient form for this, so we don't have to do a
106 // lot of extra uniquing.
107 MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
108 if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
109 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
110 RefKind = MCSymbolRefExpr::VK_GOTPAGE;
111 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
112 AArch64II::MO_PAGEOFF)
113 RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
114 else
115 llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
116 } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
117 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
118 RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
119 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
120 AArch64II::MO_PAGEOFF)
121 RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
122 else
123 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
124 } else {
125 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
126 RefKind = MCSymbolRefExpr::VK_PAGE;
127 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
128 AArch64II::MO_PAGEOFF)
129 RefKind = MCSymbolRefExpr::VK_PAGEOFF;
130 }
131 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
132 if (!MO.isJTI() && MO.getOffset())
133 Expr = MCBinaryExpr::createAdd(
134 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
135 return MCOperand::createExpr(Expr);
136 }
137
lowerSymbolOperandELF(const MachineOperand & MO,MCSymbol * Sym) const138 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
139 MCSymbol *Sym) const {
140 uint32_t RefFlags = 0;
141
142 if (MO.getTargetFlags() & AArch64II::MO_GOT)
143 RefFlags |= AArch64MCExpr::VK_GOT;
144 else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
145 TLSModel::Model Model;
146 if (MO.isGlobal()) {
147 const GlobalValue *GV = MO.getGlobal();
148 Model = Printer.TM.getTLSModel(GV);
149 if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
150 Model == TLSModel::LocalDynamic)
151 Model = TLSModel::GeneralDynamic;
152
153 } else {
154 assert(MO.isSymbol() &&
155 StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
156 "unexpected external TLS symbol");
157 // The general dynamic access sequence is used to get the
158 // address of _TLS_MODULE_BASE_.
159 Model = TLSModel::GeneralDynamic;
160 }
161 switch (Model) {
162 case TLSModel::InitialExec:
163 RefFlags |= AArch64MCExpr::VK_GOTTPREL;
164 break;
165 case TLSModel::LocalExec:
166 RefFlags |= AArch64MCExpr::VK_TPREL;
167 break;
168 case TLSModel::LocalDynamic:
169 RefFlags |= AArch64MCExpr::VK_DTPREL;
170 break;
171 case TLSModel::GeneralDynamic:
172 RefFlags |= AArch64MCExpr::VK_TLSDESC;
173 break;
174 }
175 } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
176 RefFlags |= AArch64MCExpr::VK_PREL;
177 } else {
178 // No modifier means this is a generic reference, classified as absolute for
179 // the cases where it matters (:abs_g0: etc).
180 RefFlags |= AArch64MCExpr::VK_ABS;
181 }
182
183 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
184 RefFlags |= AArch64MCExpr::VK_PAGE;
185 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
186 AArch64II::MO_PAGEOFF)
187 RefFlags |= AArch64MCExpr::VK_PAGEOFF;
188 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
189 RefFlags |= AArch64MCExpr::VK_G3;
190 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
191 RefFlags |= AArch64MCExpr::VK_G2;
192 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
193 RefFlags |= AArch64MCExpr::VK_G1;
194 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
195 RefFlags |= AArch64MCExpr::VK_G0;
196 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
197 RefFlags |= AArch64MCExpr::VK_HI12;
198
199 if (MO.getTargetFlags() & AArch64II::MO_NC)
200 RefFlags |= AArch64MCExpr::VK_NC;
201
202 const MCExpr *Expr =
203 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
204 if (!MO.isJTI() && MO.getOffset())
205 Expr = MCBinaryExpr::createAdd(
206 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
207
208 AArch64MCExpr::VariantKind RefKind;
209 RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
210 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
211
212 return MCOperand::createExpr(Expr);
213 }
214
lowerSymbolOperandCOFF(const MachineOperand & MO,MCSymbol * Sym) const215 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
216 MCSymbol *Sym) const {
217 uint32_t RefFlags = 0;
218
219 if (MO.getTargetFlags() & AArch64II::MO_TLS) {
220 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
221 RefFlags |= AArch64MCExpr::VK_SECREL_LO12;
222 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
223 AArch64II::MO_HI12)
224 RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
225
226 } else if (MO.getTargetFlags() & AArch64II::MO_S) {
227 RefFlags |= AArch64MCExpr::VK_SABS;
228 } else {
229 RefFlags |= AArch64MCExpr::VK_ABS;
230
231 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
232 RefFlags |= AArch64MCExpr::VK_PAGE;
233 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
234 AArch64II::MO_PAGEOFF)
235 RefFlags |= AArch64MCExpr::VK_PAGEOFF | AArch64MCExpr::VK_NC;
236 }
237
238 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
239 RefFlags |= AArch64MCExpr::VK_G3;
240 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
241 RefFlags |= AArch64MCExpr::VK_G2;
242 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
243 RefFlags |= AArch64MCExpr::VK_G1;
244 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
245 RefFlags |= AArch64MCExpr::VK_G0;
246
247 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
248 // because setting VK_NC for others would mean setting their respective
249 // RefFlags correctly. We should do this in a separate patch.
250 if (MO.getTargetFlags() & AArch64II::MO_NC) {
251 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
252 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
253 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
254 RefFlags |= AArch64MCExpr::VK_NC;
255 }
256
257 const MCExpr *Expr =
258 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
259 if (!MO.isJTI() && MO.getOffset())
260 Expr = MCBinaryExpr::createAdd(
261 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
262
263 auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
264 assert(RefKind != AArch64MCExpr::VK_INVALID &&
265 "Invalid relocation requested");
266 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
267
268 return MCOperand::createExpr(Expr);
269 }
270
LowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const271 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
272 MCSymbol *Sym) const {
273 if (Printer.TM.getTargetTriple().isOSDarwin())
274 return lowerSymbolOperandDarwin(MO, Sym);
275 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
276 return lowerSymbolOperandCOFF(MO, Sym);
277
278 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
279 return lowerSymbolOperandELF(MO, Sym);
280 }
281
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const282 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
283 MCOperand &MCOp) const {
284 switch (MO.getType()) {
285 default:
286 llvm_unreachable("unknown operand type");
287 case MachineOperand::MO_Register:
288 // Ignore all implicit register operands.
289 if (MO.isImplicit())
290 return false;
291 MCOp = MCOperand::createReg(MO.getReg());
292 break;
293 case MachineOperand::MO_RegisterMask:
294 // Regmasks are like implicit defs.
295 return false;
296 case MachineOperand::MO_Immediate:
297 MCOp = MCOperand::createImm(MO.getImm());
298 break;
299 case MachineOperand::MO_MachineBasicBlock:
300 MCOp = MCOperand::createExpr(
301 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
302 break;
303 case MachineOperand::MO_GlobalAddress:
304 MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
305 break;
306 case MachineOperand::MO_ExternalSymbol:
307 MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
308 break;
309 case MachineOperand::MO_MCSymbol:
310 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
311 break;
312 case MachineOperand::MO_JumpTableIndex:
313 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
314 break;
315 case MachineOperand::MO_ConstantPoolIndex:
316 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
317 break;
318 case MachineOperand::MO_BlockAddress:
319 MCOp = LowerSymbolOperand(
320 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
321 break;
322 }
323 return true;
324 }
325
Lower(const MachineInstr * MI,MCInst & OutMI) const326 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
327 OutMI.setOpcode(MI->getOpcode());
328
329 for (const MachineOperand &MO : MI->operands()) {
330 MCOperand MCOp;
331 if (lowerOperand(MO, MCOp))
332 OutMI.addOperand(MCOp);
333 }
334
335 switch (OutMI.getOpcode()) {
336 case AArch64::CATCHRET:
337 OutMI = MCInst();
338 OutMI.setOpcode(AArch64::RET);
339 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
340 break;
341 case AArch64::CLEANUPRET:
342 OutMI = MCInst();
343 OutMI.setOpcode(AArch64::RET);
344 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
345 break;
346 }
347 }
348