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

source code of llvm/lib/Target/AArch64/AArch64MCInstLower.cpp