LLVM 24.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"
16#include "AArch64Subtarget.h"
23#include "llvm/IR/Function.h"
24#include "llvm/IR/Mangler.h"
25#include "llvm/IR/Module.h"
26#include "llvm/MC/MCContext.h"
27#include "llvm/MC/MCExpr.h"
28#include "llvm/MC/MCInst.h"
29#include "llvm/MC/MCStreamer.h"
30#include "llvm/Object/COFF.h"
34using namespace llvm;
35using namespace llvm::object;
36
39
44
46 unsigned TargetFlags) const {
47 const Triple &TheTriple = GV->getParent()->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 =
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 =
75 MCSymbol *MangledSym = Ctx.getOrCreateSymbol(MangledName.value());
76 if (!cast<Function>(GV)->hasMetadata("arm64ec_hasguestexit")) {
77 Printer.OutStreamer->emitSymbolAttribute(Printer.getSymbol(GV),
79 Printer.OutStreamer->emitAssignment(
80 Printer.getSymbol(GV), MCSymbolRefExpr::create(MangledSym, Ctx));
81 Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);
82 Printer.OutStreamer->emitAssignment(
83 MangledSym, MCSymbolRefExpr::create(Printer.getSymbol(GV), Ctx));
84 }
85
86 if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)
87 return MangledSym;
88 }
89
90 return Printer.getSymbol(GV);
91 }
92
94
95 if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&
96 TheTriple.isWindowsArm64EC() &&
97 !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&
98 isa<Function>(GV)) {
99 // __imp_aux is specific to arm64EC; it represents the actual address of
100 // an imported function without any thunks.
101 //
102 // If we see a reference to an "aux" symbol, also emit a reference to the
103 // corresponding non-aux symbol. Otherwise, the Microsoft linker behaves
104 // strangely when linking against x64 import libraries.
105 //
106 // emitSymbolAttribute() doesn't have any real effect here; it just
107 // ensures the symbol name appears in the assembly without any
108 // side-effects. It might make sense to design a cleaner way to express
109 // this.
110 Name = "__imp_";
111 Printer.TM.getNameWithPrefix(Name, GV,
112 Printer.getObjFileLowering().getMangler());
113 MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);
114 Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);
115
116 Name = "__imp_aux_";
117 } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {
118 Name = "__imp_";
119 } else if (TargetFlags & AArch64II::MO_COFFSTUB) {
120 Name = ".refptr.";
121 }
122 Printer.TM.getNameWithPrefix(Name, GV,
123 Printer.getObjFileLowering().getMangler());
124
125 MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
126
127 if (TargetFlags & AArch64II::MO_COFFSTUB) {
128 MachineModuleInfoCOFF &MMICOFF =
129 Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
131 MMICOFF.getGVStubEntry(MCSym);
132
133 if (!StubSym.getPointer())
134 StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
135 }
136
137 return MCSym;
138}
139
140MCSymbol *
142 return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
143}
144
146 MCSymbol *Sym) const {
147 // FIXME: We would like an efficient form for this, so we don't have to do a
148 // lot of extra uniquing.
149 auto Spec = AArch64::S_None;
150 if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
153 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
156 else
157 llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
158 } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
161 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
164 else
165 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
166 } else {
169 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
172 }
173 // TODO: Migrate to MCSpecifierExpr::create like ELF.
174 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);
175 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
177 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
178 return MCOperand::createExpr(Expr);
179}
180
182 MCSymbol *Sym) const {
183 uint32_t RefFlags = 0;
184
186 const MachineFunction *MF = Printer.MF;
187 RefFlags |= (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
190 } else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
191 TLSModel::Model Model;
192 if (MO.isGlobal()) {
193 const MachineFunction *MF = Printer.MF;
196 } else {
197 const GlobalValue *GV = MO.getGlobal();
198 Model = Printer.TM.getTLSModel(GV);
200 .getCLOpts()
201 .elf_ldtls_generation &&
202 Model == TLSModel::LocalDynamic)
204 }
205 } else {
206 assert(MO.isSymbol() &&
207 StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
208 "unexpected external TLS symbol");
209 // The general dynamic access sequence is used to get the
210 // address of _TLS_MODULE_BASE_.
212 }
213 switch (Model) {
215 RefFlags |= AArch64::S_GOTTPREL;
216 break;
218 RefFlags |= AArch64::S_TPREL;
219 break;
221 RefFlags |= AArch64::S_DTPREL;
222 break;
224 // TODO: it's probably better to introduce MO_TLS_AUTH or smth and avoid
225 // running hasELFSignedGOT() every time, but existing flags already
226 // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and
227 // making the field wider breaks static assertions.
228 const MachineFunction *MF = Printer.MF;
229 RefFlags |= MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
232 break;
233 }
234 }
235 } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
236 RefFlags |= AArch64::S_PREL;
237 } else {
238 // No modifier means this is a generic reference, classified as absolute for
239 // the cases where it matters (:abs_g0: etc).
240 RefFlags |= AArch64::S_ABS;
241 }
242
244 RefFlags |= AArch64::S_PAGE;
245 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
247 RefFlags |= AArch64::S_PAGEOFF;
249 RefFlags |= AArch64::S_G3;
251 RefFlags |= AArch64::S_G2;
253 RefFlags |= AArch64::S_G1;
255 RefFlags |= AArch64::S_G0;
257 RefFlags |= AArch64::S_HI12;
258
260 RefFlags |= AArch64::S_NC;
261
262 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
263 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
265 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
266
267 Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);
268 return MCOperand::createExpr(Expr);
269}
270
272 MCSymbol *Sym) const {
273 uint32_t RefFlags = 0;
274
277 RefFlags |= AArch64::S_SECREL_LO12;
278 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
280 RefFlags |= AArch64::S_SECREL_HI12;
281
282 } else if (MO.getTargetFlags() & AArch64II::MO_S) {
283 RefFlags |= AArch64::S_SABS;
284 } else {
285 RefFlags |= AArch64::S_ABS;
286
288 RefFlags |= AArch64::S_PAGE;
289 else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
291 RefFlags |= AArch64::S_PAGEOFF | AArch64::S_NC;
292 }
293
295 RefFlags |= AArch64::S_G3;
297 RefFlags |= AArch64::S_G2;
299 RefFlags |= AArch64::S_G1;
301 RefFlags |= AArch64::S_G0;
302
303 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
304 // because setting VK_NC for others would mean setting their respective
305 // RefFlags correctly. We should do this in a separate patch.
306 if (MO.getTargetFlags() & AArch64II::MO_NC) {
307 auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
308 if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
309 MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
310 RefFlags |= AArch64::S_NC;
311 }
312
313 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
314 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
316 Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
317
318 Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);
319 return MCOperand::createExpr(Expr);
320}
321
323 MCSymbol *Sym) const {
324 if (Printer.TM.getTargetTriple().isOSBinFormatMachO())
325 return lowerSymbolOperandMachO(MO, Sym);
326 if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
327 return lowerSymbolOperandCOFF(MO, Sym);
328
329 assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
330 return lowerSymbolOperandELF(MO, Sym);
331}
332
334 MCOperand &MCOp) const {
335 switch (MO.getType()) {
336 default:
337 llvm_unreachable("unknown operand type");
339 // Ignore all implicit register operands.
340 if (MO.isImplicit())
341 return false;
342 MCOp = MCOperand::createReg(MO.getReg());
343 break;
345 // Regmasks are like implicit defs.
346 return false;
348 MCOp = MCOperand::createImm(MO.getImm());
349 break;
351 MCOp = LowerSymbolOperand(MO, MO.getMBB()->getSymbol());
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}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu next use printer
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
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
const AArch64Options & getCLOpts() const
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:95
bool hasExternalLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:342
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
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:213
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
MachineModuleInfoCOFF - This is a MachineModuleInfoImpl implementation for COFF targets.
StubValueTy & getGVStubEntry(MCSymbol *Sym)
PointerIntPair< MCSymbol *, 1, bool > StubValueTy
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
int64_t getImm() 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
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.
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:328
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:888
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
bool isOSBinFormatCOFF() const
Tests whether the OS uses the COFF binary format.
Definition Triple.h:870
bool isOSWindows() const
Tests whether the OS is Windows.
Definition Triple.h:778
bool isWindowsArm64EC() const
Definition Triple.h:798
#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 "....
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::optional< std::string > getArm64ECMangledFunctionName(StringRef Name)
Returns the ARM64EC mangled function name unless the input is already mangled.
Definition Mangler.cpp:292
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
@ MCSA_Global
.type _foo, @gnu_unique_object
@ MCSA_WeakAntiDep
.weak_anti_dep (COFF)