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/Function.h"
22 #include "llvm/IR/Mangler.h"
23 #include "llvm/MC/MCContext.h"
24 #include "llvm/MC/MCExpr.h"
25 #include "llvm/MC/MCInst.h"
26 #include "llvm/MC/MCStreamer.h"
27 #include "llvm/Object/COFF.h"
28 #include "llvm/Support/CodeGen.h"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Target/TargetLoweringObjectFile.h"
31 #include "llvm/Target/TargetMachine.h"
32 using namespace llvm;
33 using namespace llvm::object;
34
35 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
36
AArch64MCInstLower(MCContext & ctx,AsmPrinter & printer)37 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
38 : Ctx(ctx), Printer(printer) {}
39
40 MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const41 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
42 return GetGlobalValueSymbol(MO.getGlobal(), MO.getTargetFlags());
43 }
44
GetGlobalValueSymbol(const GlobalValue * GV,unsigned TargetFlags) const45 MCSymbol *AArch64MCInstLower::GetGlobalValueSymbol(const GlobalValue *GV,
46 unsigned TargetFlags) const {
47 const Triple &TheTriple = Printer.TM.getTargetTriple();
48 if (!TheTriple.isOSBinFormatCOFF())
49 return Printer.getSymbolPreferLocal(*GV);
50
51 assert(TheTriple.isOSWindows() &&
52 "Windows is the only supported COFF target");
53
54 bool IsIndirect =
55 (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
56 if (!IsIndirect) {
57 // For ARM64EC, symbol lookup in the MSVC linker has limited awareness
58 // of ARM64EC mangling ("#"/"$$h"). So object files need to refer to both
59 // the mangled and unmangled names of ARM64EC symbols, even if they aren't
60 // actually used by any relocations. Emit the necessary references here.
61 if (!TheTriple.isWindowsArm64EC() || !isa<Function>(GV) ||
62 !GV->hasExternalLinkage())
63 return Printer.getSymbol(GV);
64
65 StringRef Name = Printer.getSymbol(GV)->getName();
66 // Don't mangle ARM64EC runtime functions.
67 static constexpr StringLiteral ExcludedFns[] = {
68 "__os_arm64x_check_icall_cfg", "__os_arm64x_dispatch_call_no_redirect",
69 "__os_arm64x_check_icall"};
70 if (is_contained(ExcludedFns, Name))
71 return Printer.getSymbol(GV);
72
73 if (std::optional<std::string> MangledName =
74 getArm64ECMangledFunctionName(Name.str())) {
75 MCSymbol *MangledSym = Ctx.getOrCreateSymbol(MangledName.value());
76 if (!cast<Function>(GV)->hasMetadata("arm64ec_hasguestexit")) {
77 Printer.OutStreamer->emitSymbolAttribute(Printer.getSymbol(GV),
78 MCSA_WeakAntiDep);
79 Printer.OutStreamer->emitAssignment(
80 Printer.getSymbol(GV),
81 MCSymbolRefExpr::create(MangledSym, MCSymbolRefExpr::VK_WEAKREF,
82 Ctx));
83 Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);
84 Printer.OutStreamer->emitAssignment(
85 MangledSym,
86 MCSymbolRefExpr::create(Printer.getSymbol(GV),
87 MCSymbolRefExpr::VK_WEAKREF, Ctx));
88 }
89
90 if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)
91 return MangledSym;
92 }
93
94 return Printer.getSymbol(GV);
95 }
96
97 SmallString<128> Name;
98
99 if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&
100 TheTriple.isWindowsArm64EC() &&
101 !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&
102 isa<Function>(GV)) {
103 // __imp_aux is specific to arm64EC; it represents the actual address of
104 // an imported function without any thunks.
105 //
106 // If we see a reference to an "aux" symbol, also emit a reference to the
107 // corresponding non-aux symbol. Otherwise, the Microsoft linker behaves
108 // strangely when linking against x64 import libararies.
109 //
110 // emitSymbolAttribute() doesn't have any real effect here; it just
111 // ensures the symbol name appears in the assembly without any
112 // side-effects. It might make sense to design a cleaner way to express
113 // this.
114 Name = "__imp_";
115 Printer.TM.getNameWithPrefix(Name, GV,
116 Printer.getObjFileLowering().getMangler());
117 MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);
118 Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);
119
120 Name = "__imp_aux_";
121 } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {
122 Name = "__imp_";
123 } else if (TargetFlags & AArch64II::MO_COFFSTUB) {
124 Name = ".refptr.";
125 }
126 Printer.TM.getNameWithPrefix(Name, GV,
127 Printer.getObjFileLowering().getMangler());
128
129 MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
130
131 if (TargetFlags & AArch64II::MO_COFFSTUB) {
132 MachineModuleInfoCOFF &MMICOFF =
133 Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
134 MachineModuleInfoImpl::StubValueTy &StubSym =
135 MMICOFF.getGVStubEntry(MCSym);
136
137 if (!StubSym.getPointer())
138 StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
139 }
140
141 return MCSym;
142 }
143
144 MCSymbol *
GetExternalSymbolSymbol(const MachineOperand & MO) const145 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
146 return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
147 }
148
lowerSymbolOperandMachO(const MachineOperand & MO,MCSymbol * Sym) const149 MCOperand AArch64MCInstLower::lowerSymbolOperandMachO(const MachineOperand &MO,
150 MCSymbol *Sym) const {
151 // FIXME: We would like an efficient form for this, so we don't have to do a
152 // lot of extra uniquing.
153 MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
154 if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
155 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
156 RefKind = MCSymbolRefExpr::VK_GOTPAGE;
157 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
158 AArch64II::MO_PAGEOFF)
159 RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
160 else
161 llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
162 } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
163 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
164 RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
165 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
166 AArch64II::MO_PAGEOFF)
167 RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
168 else
169 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
170 } else {
171 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
172 RefKind = MCSymbolRefExpr::VK_PAGE;
173 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
174 AArch64II::MO_PAGEOFF)
175 RefKind = MCSymbolRefExpr::VK_PAGEOFF;
176 }
177 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
178 if (!MO.isJTI() && MO.getOffset())
179 Expr = MCBinaryExpr::createAdd(
180 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
181 return MCOperand::createExpr(Expr);
182 }
183
lowerSymbolOperandELF(const MachineOperand & MO,MCSymbol * Sym) const184 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
185 MCSymbol *Sym) const {
186 uint32_t RefFlags = 0;
187
188 if (MO.getTargetFlags() & AArch64II::MO_GOT)
189 RefFlags |= AArch64MCExpr::VK_GOT;
190 else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
191 TLSModel::Model Model;
192 if (MO.isGlobal()) {
193 const GlobalValue *GV = MO.getGlobal();
194 Model = Printer.TM.getTLSModel(GV);
195 if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
196 Model == TLSModel::LocalDynamic)
197 Model = TLSModel::GeneralDynamic;
198
199 } else {
200 assert(MO.isSymbol() &&
201 StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
202 "unexpected external TLS symbol");
203 // The general dynamic access sequence is used to get the
204 // address of _TLS_MODULE_BASE_.
205 Model = TLSModel::GeneralDynamic;
206 }
207 switch (Model) {
208 case TLSModel::InitialExec:
209 RefFlags |= AArch64MCExpr::VK_GOTTPREL;
210 break;
211 case TLSModel::LocalExec:
212 RefFlags |= AArch64MCExpr::VK_TPREL;
213 break;
214 case TLSModel::LocalDynamic:
215 RefFlags |= AArch64MCExpr::VK_DTPREL;
216 break;
217 case TLSModel::GeneralDynamic:
218 RefFlags |= AArch64MCExpr::VK_TLSDESC;
219 break;
220 }
221 } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
222 RefFlags |= AArch64MCExpr::VK_PREL;
223 } else {
224 // No modifier means this is a generic reference, classified as absolute for
225 // the cases where it matters (:abs_g0: etc).
226 RefFlags |= AArch64MCExpr::VK_ABS;
227 }
228
229 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
230 RefFlags |= AArch64MCExpr::VK_PAGE;
231 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
232 AArch64II::MO_PAGEOFF)
233 RefFlags |= AArch64MCExpr::VK_PAGEOFF;
234 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
235 RefFlags |= AArch64MCExpr::VK_G3;
236 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
237 RefFlags |= AArch64MCExpr::VK_G2;
238 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
239 RefFlags |= AArch64MCExpr::VK_G1;
240 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
241 RefFlags |= AArch64MCExpr::VK_G0;
242 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
243 RefFlags |= AArch64MCExpr::VK_HI12;
244
245 if (MO.getTargetFlags() & AArch64II::MO_NC)
246 RefFlags |= AArch64MCExpr::VK_NC;
247
248 const MCExpr *Expr =
249 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
250 if (!MO.isJTI() && MO.getOffset())
251 Expr = MCBinaryExpr::createAdd(
252 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
253
254 AArch64MCExpr::VariantKind RefKind;
255 RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
256 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
257
258 return MCOperand::createExpr(Expr);
259 }
260
lowerSymbolOperandCOFF(const MachineOperand & MO,MCSymbol * Sym) const261 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
262 MCSymbol *Sym) const {
263 uint32_t RefFlags = 0;
264
265 if (MO.getTargetFlags() & AArch64II::MO_TLS) {
266 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
267 RefFlags |= AArch64MCExpr::VK_SECREL_LO12;
268 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
269 AArch64II::MO_HI12)
270 RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
271
272 } else if (MO.getTargetFlags() & AArch64II::MO_S) {
273 RefFlags |= AArch64MCExpr::VK_SABS;
274 } else {
275 RefFlags |= AArch64MCExpr::VK_ABS;
276
277 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
278 RefFlags |= AArch64MCExpr::VK_PAGE;
279 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
280 AArch64II::MO_PAGEOFF)
281 RefFlags |= AArch64MCExpr::VK_PAGEOFF | AArch64MCExpr::VK_NC;
282 }
283
284 if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
285 RefFlags |= AArch64MCExpr::VK_G3;
286 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
287 RefFlags |= AArch64MCExpr::VK_G2;
288 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
289 RefFlags |= AArch64MCExpr::VK_G1;
290 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
291 RefFlags |= AArch64MCExpr::VK_G0;
292
293 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
294 // because setting VK_NC for others would mean setting their respective
295 // RefFlags correctly. We should do this in a separate patch.
296 if (MO.getTargetFlags() & AArch64II::MO_NC) {
297 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
298 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
299 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
300 RefFlags |= AArch64MCExpr::VK_NC;
301 }
302
303 const MCExpr *Expr =
304 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
305 if (!MO.isJTI() && MO.getOffset())
306 Expr = MCBinaryExpr::createAdd(
307 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
308
309 auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
310 assert(RefKind != AArch64MCExpr::VK_INVALID &&
311 "Invalid relocation requested");
312 Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
313
314 return MCOperand::createExpr(Expr);
315 }
316
LowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const317 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
318 MCSymbol *Sym) const {
319 if (Printer.TM.getTargetTriple().isOSBinFormatMachO())
320 return lowerSymbolOperandMachO(MO, Sym);
321 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
322 return lowerSymbolOperandCOFF(MO, Sym);
323
324 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
325 return lowerSymbolOperandELF(MO, Sym);
326 }
327
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const328 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
329 MCOperand &MCOp) const {
330 switch (MO.getType()) {
331 default:
332 llvm_unreachable("unknown operand type");
333 case MachineOperand::MO_Register:
334 // Ignore all implicit register operands.
335 if (MO.isImplicit())
336 return false;
337 MCOp = MCOperand::createReg(MO.getReg());
338 break;
339 case MachineOperand::MO_RegisterMask:
340 // Regmasks are like implicit defs.
341 return false;
342 case MachineOperand::MO_Immediate:
343 MCOp = MCOperand::createImm(MO.getImm());
344 break;
345 case MachineOperand::MO_MachineBasicBlock:
346 MCOp = MCOperand::createExpr(
347 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
348 break;
349 case MachineOperand::MO_GlobalAddress:
350 MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
351 break;
352 case MachineOperand::MO_ExternalSymbol:
353 MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
354 break;
355 case MachineOperand::MO_MCSymbol:
356 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
357 break;
358 case MachineOperand::MO_JumpTableIndex:
359 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
360 break;
361 case MachineOperand::MO_ConstantPoolIndex:
362 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
363 break;
364 case MachineOperand::MO_BlockAddress:
365 MCOp = LowerSymbolOperand(
366 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
367 break;
368 }
369 return true;
370 }
371
Lower(const MachineInstr * MI,MCInst & OutMI) const372 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
373 OutMI.setOpcode(MI->getOpcode());
374
375 for (const MachineOperand &MO : MI->operands()) {
376 MCOperand MCOp;
377 if (lowerOperand(MO, MCOp))
378 OutMI.addOperand(MCOp);
379 }
380
381 switch (OutMI.getOpcode()) {
382 case AArch64::CATCHRET:
383 OutMI = MCInst();
384 OutMI.setOpcode(AArch64::RET);
385 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
386 break;
387 case AArch64::CLEANUPRET:
388 OutMI = MCInst();
389 OutMI.setOpcode(AArch64::RET);
390 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
391 break;
392 }
393 }
394