LLVM 22.0.0git
AArch64MCInstLower.cpp
Go to the documentation of this file.
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"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/Mangler.h"
24#include "llvm/MC/MCContext.h"
25#include "llvm/MC/MCExpr.h"
26#include "llvm/MC/MCInst.h"
27#include "llvm/MC/MCStreamer.h"
28#include "llvm/Object/COFF.h"
33using namespace llvm;
34using namespace llvm::object;
35
37
39 : Ctx(ctx), Printer(printer) {}
40
44}
45
47 unsigned TargetFlags) const {
48 const Triple &TheTriple = Printer.TM.getTargetTriple();
49 if (!TheTriple.isOSBinFormatCOFF())
50 return Printer.getSymbolPreferLocal(*GV);
51
52 assert(TheTriple.isOSWindows() &&
53 "Windows is the only supported COFF target");
54
55 bool IsIndirect =
57 if (!IsIndirect) {
58 // For ARM64EC, symbol lookup in the MSVC linker has limited awareness
59 // of ARM64EC mangling ("#"/"$$h"). So object files need to refer to both
60 // the mangled and unmangled names of ARM64EC symbols, even if they aren't
61 // actually used by any relocations. Emit the necessary references here.
62 if (!TheTriple.isWindowsArm64EC() || !isa<Function>(GV) ||
63 !GV->hasExternalLinkage())
64 return Printer.getSymbol(GV);
65
66 StringRef Name = Printer.getSymbol(GV)->getName();
67 // Don't mangle ARM64EC runtime functions.
68 static constexpr StringLiteral ExcludedFns[] = {
69 "__os_arm64x_check_icall_cfg", "__os_arm64x_dispatch_call_no_redirect",
70 "__os_arm64x_check_icall"};
71 if (is_contained(ExcludedFns, Name))
72 return Printer.getSymbol(GV);
73
74 if (std::optional<std::string> MangledName =
76 MCSymbol *MangledSym = Ctx.getOrCreateSymbol(MangledName.value());
77 if (!cast<Function>(GV)->hasMetadata("arm64ec_hasguestexit")) {
78 Printer.OutStreamer->emitSymbolAttribute(Printer.getSymbol(GV),
80 Printer.OutStreamer->emitAssignment(
81 Printer.getSymbol(GV), MCSymbolRefExpr::create(MangledSym, Ctx));
82 Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);
83 Printer.OutStreamer->emitAssignment(
84 MangledSym, MCSymbolRefExpr::create(Printer.getSymbol(GV), Ctx));
85 }
86
87 if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)
88 return MangledSym;
89 }
90
91 return Printer.getSymbol(GV);
92 }
93
95
96 if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&
97 TheTriple.isWindowsArm64EC() &&
98 !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&
99 isa<Function>(GV)) {
100 // __imp_aux is specific to arm64EC; it represents the actual address of
101 // an imported function without any thunks.
102 //
103 // If we see a reference to an "aux" symbol, also emit a reference to the
104 // corresponding non-aux symbol. Otherwise, the Microsoft linker behaves
105 // strangely when linking against x64 import libararies.
106 //
107 // emitSymbolAttribute() doesn't have any real effect here; it just
108 // ensures the symbol name appears in the assembly without any
109 // side-effects. It might make sense to design a cleaner way to express
110 // this.
111 Name = "__imp_";
112 Printer.TM.getNameWithPrefix(Name, GV,
113 Printer.getObjFileLowering().getMangler());
114 MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);
115 Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);
116
117 Name = "__imp_aux_";
118 } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {
119 Name = "__imp_";
120 } else if (TargetFlags & AArch64II::MO_COFFSTUB) {
121 Name = ".refptr.";
122 }
123 Printer.TM.getNameWithPrefix(Name, GV,
124 Printer.getObjFileLowering().getMangler());
125
126 MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
127
128 if (TargetFlags & AArch64II::MO_COFFSTUB) {
129 MachineModuleInfoCOFF &MMICOFF =
132 MMICOFF.getGVStubEntry(MCSym);
133
134 if (!StubSym.getPointer())
135 StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
136 }
137
138 return MCSym;
139}
140
141MCSymbol *
143 return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
144}
145
147 MCSymbol *Sym) const {
148 // FIXME: We would like an efficient form for this, so we don't have to do a
149 // lot of extra uniquing.
150 auto Spec = AArch64::S_None;
151 if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
154 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
157 else
158 llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
159 } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
162 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
165 else
166 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
167 } else {
170 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
173 }
174 // TODO: Migrate to MCSpecifierExpr::create like ELF.
175 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);
176 if (!MO.isJTI() && MO.getOffset())
178 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
179 return MCOperand::createExpr(Expr);
180}
181
183 MCSymbol *Sym) const {
184 uint32_t RefFlags = 0;
185
187 const MachineFunction *MF = MO.getParent()->getParent()->getParent();
188 RefFlags |= (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
191 } else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
192 TLSModel::Model Model;
193 if (MO.isGlobal()) {
194 const MachineFunction *MF = MO.getParent()->getParent()->getParent();
197 } else {
198 const GlobalValue *GV = MO.getGlobal();
199 Model = Printer.TM.getTLSModel(GV);
201 Model == TLSModel::LocalDynamic)
203 }
204 } else {
205 assert(MO.isSymbol() &&
206 StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
207 "unexpected external TLS symbol");
208 // The general dynamic access sequence is used to get the
209 // address of _TLS_MODULE_BASE_.
211 }
212 switch (Model) {
214 RefFlags |= AArch64::S_GOTTPREL;
215 break;
217 RefFlags |= AArch64::S_TPREL;
218 break;
220 RefFlags |= AArch64::S_DTPREL;
221 break;
223 // TODO: it's probably better to introduce MO_TLS_AUTH or smth and avoid
224 // running hasELFSignedGOT() every time, but existing flags already
225 // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and
226 // making the field wider breaks static assertions.
227 const MachineFunction *MF = MO.getParent()->getParent()->getParent();
228 RefFlags |= MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
231 break;
232 }
233 }
234 } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
235 RefFlags |= AArch64::S_PREL;
236 } else {
237 // No modifier means this is a generic reference, classified as absolute for
238 // the cases where it matters (:abs_g0: etc).
239 RefFlags |= AArch64::S_ABS;
240 }
241
243 RefFlags |= AArch64::S_PAGE;
244 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
246 RefFlags |= AArch64::S_PAGEOFF;
248 RefFlags |= AArch64::S_G3;
250 RefFlags |= AArch64::S_G2;
252 RefFlags |= AArch64::S_G1;
254 RefFlags |= AArch64::S_G0;
256 RefFlags |= AArch64::S_HI12;
257
259 RefFlags |= AArch64::S_NC;
260
261 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
262 if (!MO.isJTI() && MO.getOffset())
264 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
265
266 Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);
267 return MCOperand::createExpr(Expr);
268}
269
271 MCSymbol *Sym) const {
272 uint32_t RefFlags = 0;
273
276 RefFlags |= AArch64::S_SECREL_LO12;
277 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
279 RefFlags |= AArch64::S_SECREL_HI12;
280
281 } else if (MO.getTargetFlags() & AArch64II::MO_S) {
282 RefFlags |= AArch64::S_SABS;
283 } else {
284 RefFlags |= AArch64::S_ABS;
285
287 RefFlags |= AArch64::S_PAGE;
288 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
290 RefFlags |= AArch64::S_PAGEOFF | AArch64::S_NC;
291 }
292
294 RefFlags |= AArch64::S_G3;
296 RefFlags |= AArch64::S_G2;
298 RefFlags |= AArch64::S_G1;
300 RefFlags |= AArch64::S_G0;
301
302 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
303 // because setting VK_NC for others would mean setting their respective
304 // RefFlags correctly. We should do this in a separate patch.
305 if (MO.getTargetFlags() & AArch64II::MO_NC) {
306 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
307 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
308 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
309 RefFlags |= AArch64::S_NC;
310 }
311
312 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
313 if (!MO.isJTI() && MO.getOffset())
315 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
316
317 Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);
318 return MCOperand::createExpr(Expr);
319}
320
322 MCSymbol *Sym) const {
323 if (Printer.TM.getTargetTriple().isOSBinFormatMachO())
324 return lowerSymbolOperandMachO(MO, Sym);
325 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
326 return lowerSymbolOperandCOFF(MO, Sym);
327
328 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
329 return lowerSymbolOperandELF(MO, Sym);
330}
331
333 MCOperand &MCOp) const {
334 switch (MO.getType()) {
335 default:
336 llvm_unreachable("unknown operand type");
338 // Ignore all implicit register operands.
339 if (MO.isImplicit())
340 return false;
341 MCOp = MCOperand::createReg(MO.getReg());
342 break;
344 // Regmasks are like implicit defs.
345 return false;
347 MCOp = MCOperand::createImm(MO.getImm());
348 break;
352 break;
355 break;
358 break;
360 MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
361 break;
363 MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
364 break;
366 MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
367 break;
369 MCOp = LowerSymbolOperand(
370 MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
371 break;
372 }
373 return true;
374}
375
377 OutMI.setOpcode(MI->getOpcode());
378
379 for (const MachineOperand &MO : MI->operands()) {
380 MCOperand MCOp;
381 if (lowerOperand(MO, MCOp))
382 OutMI.addOperand(MCOp);
383 }
384
385 switch (OutMI.getOpcode()) {
386 case AArch64::CATCHRET:
387 OutMI = MCInst();
388 OutMI.setOpcode(AArch64::RET);
389 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
390 break;
391 case AArch64::CLEANUPRET:
392 OutMI = MCInst();
393 OutMI.setOpcode(AArch64::RET);
394 OutMI.addOperand(MCOperand::createReg(AArch64::LR));
395 break;
396 }
397}
cl::opt< bool > EnableAArch64ELFLocalDynamicTLSGeneration("aarch64-elf-ldtls-generation", cl::Hidden, cl::desc("Allow AArch64 Local Dynamic TLS code generation"), cl::init(false))
cl::opt< bool > EnableAArch64ELFLocalDynamicTLSGeneration
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
dxil pretty printer
dxil pretty DXIL Metadata Pretty Printer
std::string Name
Symbol * Sym
Definition: ELF_riscv.cpp:479
IRTranslator LLVM IR MI
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
MCSymbol * GetExternalSymbolSymbol(const MachineOperand &MO) const
MCOperand lowerSymbolOperandCOFF(const MachineOperand &MO, MCSymbol *Sym) const
MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const
MCSymbol * GetGlobalValueSymbol(const GlobalValue *GV, unsigned TargetFlags) const
MCOperand lowerSymbolOperandELF(const MachineOperand &MO, MCSymbol *Sym) const
AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
void Lower(const MachineInstr *MI, MCInst &OutMI) const
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
MCSymbol * GetGlobalAddressSymbol(const MachineOperand &MO) const
MCOperand lowerSymbolOperandMachO(const MachineOperand &MO, MCSymbol *Sym) const
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:90
const TargetLoweringObjectFile & getObjFileLowering() const
Return information about object file lowering.
Definition: AsmPrinter.cpp:413
MCSymbol * getSymbol(const GlobalValue *GV) const
Definition: AsmPrinter.cpp:706
TargetMachine & TM
Target machine description.
Definition: AsmPrinter.h:93
virtual MCSymbol * GetCPISymbol(unsigned CPID) const
Return the symbol for the specified constant pool entry.
MCSymbol * GetJTISymbol(unsigned JTID, bool isLinkerPrivate=false) const
Return the symbol for the specified jump table entry.
MCSymbol * getSymbolPreferLocal(const GlobalValue &GV) const
Similar to getSymbol() but preferred for references.
Definition: AsmPrinter.cpp:710
MachineModuleInfo * MMI
This is a pointer to the current MachineModuleInfo.
Definition: AsmPrinter.h:111
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:105
MCSymbol * GetBlockAddressSymbol(const BlockAddress *BA) const
Return the MCSymbol used to satisfy BlockAddress uses of the specified basic block.
MCSymbol * GetExternalSymbolSymbol(const Twine &Sym) const
Return the MCSymbol for the specified ExternalSymbol.
bool hasExternalLinkage() const
Definition: GlobalValue.h:513
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.h:343
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:212
Context object for machine code objects.
Definition: MCContext.h:83
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Definition: MCContext.cpp:203
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:188
unsigned getOpcode() const
Definition: MCInst.h:202
void addOperand(const MCOperand Op)
Definition: MCInst.h:215
void setOpcode(unsigned Op)
Definition: MCInst.h:201
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:40
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:166
static MCOperand createReg(MCRegister Reg)
Definition: MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:145
static const MCSpecifierExpr * create(const MCExpr *Expr, Spec S, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.cpp:743
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:42
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:188
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
Definition: MachineInstr.h:72
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:359
MachineModuleInfoCOFF - This is a MachineModuleInfoImpl implementation for COFF targets.
StubValueTy & getGVStubEntry(MCSymbol *Sym)
Ty & getObjFileInfo()
Keep track of various per-module pieces of information for backends that would like to do so.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
int64_t getImm() const
bool isImplicit() const
MachineBasicBlock * getMBB() const
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
bool isJTI() const
isJTI - Tests if this is a MO_JumpTableIndex operand.
const BlockAddress * getBlockAddress() const
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
unsigned getTargetFlags() const
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
MCSymbol * getMCSymbol() const
@ MO_Immediate
Immediate operand.
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_RegisterMask
Mask of preserved registers.
@ MO_BlockAddress
Address of a basic block.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
int64_t getOffset() const
Return the offset from the symbol in this operand.
PointerIntPair - This class implements a pair of a pointer and small integer.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition: StringRef.h:862
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
TLSModel::Model getTLSModel(const GlobalValue *GV) const
Returns the TLS model which should be used for the given global variable.
const Triple & getTargetTriple() const
void getNameWithPrefix(SmallVectorImpl< char > &Name, const GlobalValue *GV, Mangler &Mang, bool MayAlwaysUsePrivate=false) const
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:47
bool isOSBinFormatMachO() const
Tests whether the environment is MachO.
Definition: Triple.h:779
bool isOSBinFormatCOFF() const
Tests whether the OS uses the COFF binary format.
Definition: Triple.h:771
bool isOSWindows() const
Tests whether the OS is Windows.
Definition: Triple.h:676
bool isWindowsArm64EC() const
Definition: Triple.h:692
bool isOSBinFormatELF() const
Tests whether the OS uses the ELF binary format.
Definition: Triple.h:766
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ MO_DLLIMPORT
MO_DLLIMPORT - On a symbol operand, this represents that the reference to the symbol is for an import...
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_S
MO_S - Indicates that the bits of the symbol operand represented by MO_G0 etc are signed.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_PREL
MO_PREL - Indicates that the bits of the symbol operand represented by MO_G0 etc are PC relative.
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_ARM64EC_CALLMANGLE
MO_ARM64EC_CALLMANGLE - Operand refers to the Arm64EC-mangled version of a symbol,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_HI12
MO_HI12 - This flag indicates that a symbol operand represents the bits 13-24 of a 64-bit address,...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
@ MO_COFFSTUB
MO_COFFSTUB - On a symbol operand "FOO", this indicates that the reference is actually to the "....
@ GeneralDynamic
Definition: CodeGen.h:46
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
LLVM_ABI std::optional< std::string > getArm64ECMangledFunctionName(StringRef Name)
Returns the ARM64EC mangled function name unless the input is already mangled.
Definition: Mangler.cpp:294
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1916
@ MCSA_Global
.type _foo, @gnu_unique_object
Definition: MCDirectives.h:30
@ MCSA_WeakAntiDep
.weak_anti_dep (COFF)
Definition: MCDirectives.h:49