Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
35267 views
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
37
AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
38
: Ctx(ctx), Printer(printer) {}
39
40
MCSymbol *
41
AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
42
return GetGlobalValueSymbol(MO.getGlobal(), MO.getTargetFlags());
43
}
44
45
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 *
145
AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
146
return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
147
}
148
149
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
184
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
261
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
317
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
328
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
372
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
395