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/AArch64AsmPrinter.cpp
35267 views
1
//===- AArch64AsmPrinter.cpp - AArch64 LLVM assembly writer ---------------===//
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 a printer that converts from our internal representation
10
// of machine-dependent LLVM code to the AArch64 assembly language.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "AArch64.h"
15
#include "AArch64MCInstLower.h"
16
#include "AArch64MachineFunctionInfo.h"
17
#include "AArch64RegisterInfo.h"
18
#include "AArch64Subtarget.h"
19
#include "AArch64TargetObjectFile.h"
20
#include "MCTargetDesc/AArch64AddressingModes.h"
21
#include "MCTargetDesc/AArch64InstPrinter.h"
22
#include "MCTargetDesc/AArch64MCExpr.h"
23
#include "MCTargetDesc/AArch64MCTargetDesc.h"
24
#include "MCTargetDesc/AArch64TargetStreamer.h"
25
#include "TargetInfo/AArch64TargetInfo.h"
26
#include "Utils/AArch64BaseInfo.h"
27
#include "llvm/ADT/SmallString.h"
28
#include "llvm/ADT/SmallVector.h"
29
#include "llvm/ADT/StringRef.h"
30
#include "llvm/ADT/Twine.h"
31
#include "llvm/BinaryFormat/COFF.h"
32
#include "llvm/BinaryFormat/ELF.h"
33
#include "llvm/BinaryFormat/MachO.h"
34
#include "llvm/CodeGen/AsmPrinter.h"
35
#include "llvm/CodeGen/FaultMaps.h"
36
#include "llvm/CodeGen/MachineBasicBlock.h"
37
#include "llvm/CodeGen/MachineFunction.h"
38
#include "llvm/CodeGen/MachineInstr.h"
39
#include "llvm/CodeGen/MachineJumpTableInfo.h"
40
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
41
#include "llvm/CodeGen/MachineOperand.h"
42
#include "llvm/CodeGen/StackMaps.h"
43
#include "llvm/CodeGen/TargetRegisterInfo.h"
44
#include "llvm/IR/DataLayout.h"
45
#include "llvm/IR/DebugInfoMetadata.h"
46
#include "llvm/IR/Module.h"
47
#include "llvm/MC/MCAsmInfo.h"
48
#include "llvm/MC/MCContext.h"
49
#include "llvm/MC/MCInst.h"
50
#include "llvm/MC/MCInstBuilder.h"
51
#include "llvm/MC/MCSectionELF.h"
52
#include "llvm/MC/MCSectionMachO.h"
53
#include "llvm/MC/MCStreamer.h"
54
#include "llvm/MC/MCSymbol.h"
55
#include "llvm/MC/TargetRegistry.h"
56
#include "llvm/Support/Casting.h"
57
#include "llvm/Support/CommandLine.h"
58
#include "llvm/Support/ErrorHandling.h"
59
#include "llvm/Support/raw_ostream.h"
60
#include "llvm/Target/TargetMachine.h"
61
#include "llvm/TargetParser/Triple.h"
62
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
63
#include <algorithm>
64
#include <cassert>
65
#include <cstdint>
66
#include <map>
67
#include <memory>
68
69
using namespace llvm;
70
71
enum PtrauthCheckMode { Default, Unchecked, Poison, Trap };
72
static cl::opt<PtrauthCheckMode> PtrauthAuthChecks(
73
"aarch64-ptrauth-auth-checks", cl::Hidden,
74
cl::values(clEnumValN(Unchecked, "none", "don't test for failure"),
75
clEnumValN(Poison, "poison", "poison on failure"),
76
clEnumValN(Trap, "trap", "trap on failure")),
77
cl::desc("Check pointer authentication auth/resign failures"),
78
cl::init(Default));
79
80
#define DEBUG_TYPE "asm-printer"
81
82
namespace {
83
84
class AArch64AsmPrinter : public AsmPrinter {
85
AArch64MCInstLower MCInstLowering;
86
FaultMaps FM;
87
const AArch64Subtarget *STI;
88
bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false;
89
90
public:
91
AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
92
: AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
93
FM(*this) {}
94
95
StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
96
97
/// Wrapper for MCInstLowering.lowerOperand() for the
98
/// tblgen'erated pseudo lowering.
99
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
100
return MCInstLowering.lowerOperand(MO, MCOp);
101
}
102
103
const MCExpr *lowerConstantPtrAuth(const ConstantPtrAuth &CPA) override;
104
105
const MCExpr *lowerBlockAddressConstant(const BlockAddress &BA) override;
106
107
void emitStartOfAsmFile(Module &M) override;
108
void emitJumpTableInfo() override;
109
std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
110
codeview::JumpTableEntrySize>
111
getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
112
const MCSymbol *BranchLabel) const override;
113
114
void emitFunctionEntryLabel() override;
115
116
void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
117
118
void LowerHardenedBRJumpTable(const MachineInstr &MI);
119
120
void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI);
121
122
void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
123
const MachineInstr &MI);
124
void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
125
const MachineInstr &MI);
126
void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
127
const MachineInstr &MI);
128
void LowerFAULTING_OP(const MachineInstr &MI);
129
130
void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
131
void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
132
void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
133
void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
134
135
typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
136
HwasanMemaccessTuple;
137
std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
138
void LowerKCFI_CHECK(const MachineInstr &MI);
139
void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
140
void emitHwasanMemaccessSymbols(Module &M);
141
142
void emitSled(const MachineInstr &MI, SledKind Kind);
143
144
// Emit the sequence for BRA/BLRA (authenticate + branch/call).
145
void emitPtrauthBranch(const MachineInstr *MI);
146
147
// Emit the sequence for AUT or AUTPAC.
148
void emitPtrauthAuthResign(const MachineInstr *MI);
149
150
// Emit the sequence to compute a discriminator into x17, or reuse AddrDisc.
151
unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc,
152
unsigned &InstsEmitted);
153
154
// Emit the sequence for LOADauthptrstatic
155
void LowerLOADauthptrstatic(const MachineInstr &MI);
156
157
// Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or
158
// adrp-add followed by PAC sign)
159
void LowerMOVaddrPAC(const MachineInstr &MI);
160
161
/// tblgen'erated driver function for lowering simple MI->MC
162
/// pseudo instructions.
163
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
164
const MachineInstr *MI);
165
166
void emitInstruction(const MachineInstr *MI) override;
167
168
void emitFunctionHeaderComment() override;
169
170
void getAnalysisUsage(AnalysisUsage &AU) const override {
171
AsmPrinter::getAnalysisUsage(AU);
172
AU.setPreservesAll();
173
}
174
175
bool runOnMachineFunction(MachineFunction &MF) override {
176
AArch64FI = MF.getInfo<AArch64FunctionInfo>();
177
STI = &MF.getSubtarget<AArch64Subtarget>();
178
179
SetupMachineFunction(MF);
180
181
if (STI->isTargetCOFF()) {
182
bool Local = MF.getFunction().hasLocalLinkage();
183
COFF::SymbolStorageClass Scl =
184
Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL;
185
int Type =
186
COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
187
188
OutStreamer->beginCOFFSymbolDef(CurrentFnSym);
189
OutStreamer->emitCOFFSymbolStorageClass(Scl);
190
OutStreamer->emitCOFFSymbolType(Type);
191
OutStreamer->endCOFFSymbolDef();
192
}
193
194
// Emit the rest of the function body.
195
emitFunctionBody();
196
197
// Emit the XRay table for this function.
198
emitXRayTable();
199
200
// We didn't modify anything.
201
return false;
202
}
203
204
const MCExpr *lowerConstant(const Constant *CV) override;
205
206
private:
207
void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
208
bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
209
bool printAsmRegInClass(const MachineOperand &MO,
210
const TargetRegisterClass *RC, unsigned AltName,
211
raw_ostream &O);
212
213
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
214
const char *ExtraCode, raw_ostream &O) override;
215
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
216
const char *ExtraCode, raw_ostream &O) override;
217
218
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
219
220
void emitFunctionBodyEnd() override;
221
void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
222
223
MCSymbol *GetCPISymbol(unsigned CPID) const override;
224
void emitEndOfAsmFile(Module &M) override;
225
226
AArch64FunctionInfo *AArch64FI = nullptr;
227
228
/// Emit the LOHs contained in AArch64FI.
229
void emitLOHs();
230
231
/// Emit instruction to set float register to zero.
232
void emitFMov0(const MachineInstr &MI);
233
234
using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
235
236
MInstToMCSymbol LOHInstToLabel;
237
238
bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
239
return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
240
}
241
242
const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
243
assert(STI);
244
return STI;
245
}
246
void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
247
MCSymbol *LazyPointer) override;
248
void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
249
MCSymbol *LazyPointer) override;
250
};
251
252
} // end anonymous namespace
253
254
void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
255
const Triple &TT = TM.getTargetTriple();
256
257
if (TT.isOSBinFormatCOFF()) {
258
// Emit an absolute @feat.00 symbol
259
MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00"));
260
OutStreamer->beginCOFFSymbolDef(S);
261
OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
262
OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL);
263
OutStreamer->endCOFFSymbolDef();
264
int64_t Feat00Value = 0;
265
266
if (M.getModuleFlag("cfguard")) {
267
// Object is CFG-aware.
268
Feat00Value |= COFF::Feat00Flags::GuardCF;
269
}
270
271
if (M.getModuleFlag("ehcontguard")) {
272
// Object also has EHCont.
273
Feat00Value |= COFF::Feat00Flags::GuardEHCont;
274
}
275
276
if (M.getModuleFlag("ms-kernel")) {
277
// Object is compiled with /kernel.
278
Feat00Value |= COFF::Feat00Flags::Kernel;
279
}
280
281
OutStreamer->emitSymbolAttribute(S, MCSA_Global);
282
OutStreamer->emitAssignment(
283
S, MCConstantExpr::create(Feat00Value, MMI->getContext()));
284
}
285
286
if (!TT.isOSBinFormatELF())
287
return;
288
289
// Assemble feature flags that may require creation of a note section.
290
unsigned Flags = 0;
291
if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
292
M.getModuleFlag("branch-target-enforcement")))
293
if (!BTE->isZero())
294
Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
295
296
if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
297
M.getModuleFlag("guarded-control-stack")))
298
if (!GCS->isZero())
299
Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
300
301
if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
302
M.getModuleFlag("sign-return-address")))
303
if (!Sign->isZero())
304
Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
305
306
uint64_t PAuthABIPlatform = -1;
307
if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
308
M.getModuleFlag("aarch64-elf-pauthabi-platform")))
309
PAuthABIPlatform = PAP->getZExtValue();
310
uint64_t PAuthABIVersion = -1;
311
if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
312
M.getModuleFlag("aarch64-elf-pauthabi-version")))
313
PAuthABIVersion = PAV->getZExtValue();
314
315
// Emit a .note.gnu.property section with the flags.
316
auto *TS =
317
static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
318
TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion);
319
}
320
321
void AArch64AsmPrinter::emitFunctionHeaderComment() {
322
const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>();
323
std::optional<std::string> OutlinerString = FI->getOutliningStyle();
324
if (OutlinerString != std::nullopt)
325
OutStreamer->getCommentOS() << ' ' << OutlinerString;
326
}
327
328
void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
329
{
330
const Function &F = MF->getFunction();
331
if (F.hasFnAttribute("patchable-function-entry")) {
332
unsigned Num;
333
if (F.getFnAttribute("patchable-function-entry")
334
.getValueAsString()
335
.getAsInteger(10, Num))
336
return;
337
emitNops(Num);
338
return;
339
}
340
341
emitSled(MI, SledKind::FUNCTION_ENTER);
342
}
343
344
void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
345
emitSled(MI, SledKind::FUNCTION_EXIT);
346
}
347
348
void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
349
emitSled(MI, SledKind::TAIL_CALL);
350
}
351
352
void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
353
static const int8_t NoopsInSledCount = 7;
354
// We want to emit the following pattern:
355
//
356
// .Lxray_sled_N:
357
// ALIGN
358
// B #32
359
// ; 7 NOP instructions (28 bytes)
360
// .tmpN
361
//
362
// We need the 28 bytes (7 instructions) because at runtime, we'd be patching
363
// over the full 32 bytes (8 instructions) with the following pattern:
364
//
365
// STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
366
// LDR W17, #12 ; W17 := function ID
367
// LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
368
// BLR X16 ; call the tracing trampoline
369
// ;DATA: 32 bits of function ID
370
// ;DATA: lower 32 bits of the address of the trampoline
371
// ;DATA: higher 32 bits of the address of the trampoline
372
// LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
373
//
374
OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
375
auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
376
OutStreamer->emitLabel(CurSled);
377
auto Target = OutContext.createTempSymbol();
378
379
// Emit "B #32" instruction, which jumps over the next 28 bytes.
380
// The operand has to be the number of 4-byte instructions to jump over,
381
// including the current instruction.
382
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
383
384
for (int8_t I = 0; I < NoopsInSledCount; I++)
385
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
386
387
OutStreamer->emitLabel(Target);
388
recordSled(CurSled, MI, Kind, 2);
389
}
390
391
// Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
392
// (built-in functions __xray_customevent/__xray_typedevent).
393
//
394
// .Lxray_event_sled_N:
395
// b 1f
396
// save x0 and x1 (and also x2 for TYPED_EVENT_CALL)
397
// set up x0 and x1 (and also x2 for TYPED_EVENT_CALL)
398
// bl __xray_CustomEvent or __xray_TypedEvent
399
// restore x0 and x1 (and also x2 for TYPED_EVENT_CALL)
400
// 1:
401
//
402
// There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL.
403
//
404
// Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT.
405
// After patching, b .+N will become a nop.
406
void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
407
bool Typed) {
408
auto &O = *OutStreamer;
409
MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
410
O.emitLabel(CurSled);
411
MCInst MovX0Op0 = MCInstBuilder(AArch64::ORRXrs)
412
.addReg(AArch64::X0)
413
.addReg(AArch64::XZR)
414
.addReg(MI.getOperand(0).getReg())
415
.addImm(0);
416
MCInst MovX1Op1 = MCInstBuilder(AArch64::ORRXrs)
417
.addReg(AArch64::X1)
418
.addReg(AArch64::XZR)
419
.addReg(MI.getOperand(1).getReg())
420
.addImm(0);
421
bool MachO = TM.getTargetTriple().isOSBinFormatMachO();
422
auto *Sym = MCSymbolRefExpr::create(
423
OutContext.getOrCreateSymbol(
424
Twine(MachO ? "_" : "") +
425
(Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")),
426
OutContext);
427
if (Typed) {
428
O.AddComment("Begin XRay typed event");
429
EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9));
430
EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
431
.addReg(AArch64::SP)
432
.addReg(AArch64::X0)
433
.addReg(AArch64::X1)
434
.addReg(AArch64::SP)
435
.addImm(-4));
436
EmitToStreamer(O, MCInstBuilder(AArch64::STRXui)
437
.addReg(AArch64::X2)
438
.addReg(AArch64::SP)
439
.addImm(2));
440
EmitToStreamer(O, MovX0Op0);
441
EmitToStreamer(O, MovX1Op1);
442
EmitToStreamer(O, MCInstBuilder(AArch64::ORRXrs)
443
.addReg(AArch64::X2)
444
.addReg(AArch64::XZR)
445
.addReg(MI.getOperand(2).getReg())
446
.addImm(0));
447
EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
448
EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui)
449
.addReg(AArch64::X2)
450
.addReg(AArch64::SP)
451
.addImm(2));
452
O.AddComment("End XRay typed event");
453
EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
454
.addReg(AArch64::SP)
455
.addReg(AArch64::X0)
456
.addReg(AArch64::X1)
457
.addReg(AArch64::SP)
458
.addImm(4));
459
460
recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2);
461
} else {
462
O.AddComment("Begin XRay custom event");
463
EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6));
464
EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
465
.addReg(AArch64::SP)
466
.addReg(AArch64::X0)
467
.addReg(AArch64::X1)
468
.addReg(AArch64::SP)
469
.addImm(-2));
470
EmitToStreamer(O, MovX0Op0);
471
EmitToStreamer(O, MovX1Op1);
472
EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
473
O.AddComment("End XRay custom event");
474
EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
475
.addReg(AArch64::SP)
476
.addReg(AArch64::X0)
477
.addReg(AArch64::X1)
478
.addReg(AArch64::SP)
479
.addImm(2));
480
481
recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2);
482
}
483
}
484
485
void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
486
Register AddrReg = MI.getOperand(0).getReg();
487
assert(std::next(MI.getIterator())->isCall() &&
488
"KCFI_CHECK not followed by a call instruction");
489
assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
490
"KCFI_CHECK call target doesn't match call operand");
491
492
// Default to using the intra-procedure-call temporary registers for
493
// comparing the hashes.
494
unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
495
if (AddrReg == AArch64::XZR) {
496
// Checking XZR makes no sense. Instead of emitting a load, zero
497
// ScratchRegs[0] and use it for the ESR AddrIndex below.
498
AddrReg = getXRegFromWReg(ScratchRegs[0]);
499
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
500
.addReg(AddrReg)
501
.addReg(AArch64::XZR)
502
.addReg(AArch64::XZR)
503
.addImm(0));
504
} else {
505
// If one of the scratch registers is used for the call target (e.g.
506
// with AArch64::TCRETURNriBTI), we can clobber another caller-saved
507
// temporary register instead (in this case, AArch64::W9) as the check
508
// is immediately followed by the call instruction.
509
for (auto &Reg : ScratchRegs) {
510
if (Reg == getWRegFromXReg(AddrReg)) {
511
Reg = AArch64::W9;
512
break;
513
}
514
}
515
assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
516
"Invalid scratch registers for KCFI_CHECK");
517
518
// Adjust the offset for patchable-function-prefix. This assumes that
519
// patchable-function-prefix is the same for all functions.
520
int64_t PrefixNops = 0;
521
(void)MI.getMF()
522
->getFunction()
523
.getFnAttribute("patchable-function-prefix")
524
.getValueAsString()
525
.getAsInteger(10, PrefixNops);
526
527
// Load the target function type hash.
528
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
529
.addReg(ScratchRegs[0])
530
.addReg(AddrReg)
531
.addImm(-(PrefixNops * 4 + 4)));
532
}
533
534
// Load the expected type hash.
535
const int64_t Type = MI.getOperand(1).getImm();
536
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
537
.addReg(ScratchRegs[1])
538
.addReg(ScratchRegs[1])
539
.addImm(Type & 0xFFFF)
540
.addImm(0));
541
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
542
.addReg(ScratchRegs[1])
543
.addReg(ScratchRegs[1])
544
.addImm((Type >> 16) & 0xFFFF)
545
.addImm(16));
546
547
// Compare the hashes and trap if there's a mismatch.
548
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs)
549
.addReg(AArch64::WZR)
550
.addReg(ScratchRegs[0])
551
.addReg(ScratchRegs[1])
552
.addImm(0));
553
554
MCSymbol *Pass = OutContext.createTempSymbol();
555
EmitToStreamer(*OutStreamer,
556
MCInstBuilder(AArch64::Bcc)
557
.addImm(AArch64CC::EQ)
558
.addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
559
560
// The base ESR is 0x8000 and the register information is encoded in bits
561
// 0-9 as follows:
562
// - 0-4: n, where the register Xn contains the target address
563
// - 5-9: m, where the register Wm contains the expected type hash
564
// Where n, m are in [0, 30].
565
unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
566
unsigned AddrIndex;
567
switch (AddrReg) {
568
default:
569
AddrIndex = AddrReg - AArch64::X0;
570
break;
571
case AArch64::FP:
572
AddrIndex = 29;
573
break;
574
case AArch64::LR:
575
AddrIndex = 30;
576
break;
577
}
578
579
assert(AddrIndex < 31 && TypeIndex < 31);
580
581
unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
582
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR));
583
OutStreamer->emitLabel(Pass);
584
}
585
586
void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
587
Register Reg = MI.getOperand(0).getReg();
588
bool IsShort =
589
((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
590
(MI.getOpcode() ==
591
AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
592
uint32_t AccessInfo = MI.getOperand(1).getImm();
593
bool IsFixedShadow =
594
((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
595
(MI.getOpcode() ==
596
AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
597
uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0;
598
599
MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
600
Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
601
if (!Sym) {
602
// FIXME: Make this work on non-ELF.
603
if (!TM.getTargetTriple().isOSBinFormatELF())
604
report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
605
606
std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
607
utostr(AccessInfo);
608
if (IsFixedShadow)
609
SymName += "_fixed_" + utostr(FixedShadowOffset);
610
if (IsShort)
611
SymName += "_short_v2";
612
Sym = OutContext.getOrCreateSymbol(SymName);
613
}
614
615
EmitToStreamer(*OutStreamer,
616
MCInstBuilder(AArch64::BL)
617
.addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
618
}
619
620
void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
621
if (HwasanMemaccessSymbols.empty())
622
return;
623
624
const Triple &TT = TM.getTargetTriple();
625
assert(TT.isOSBinFormatELF());
626
std::unique_ptr<MCSubtargetInfo> STI(
627
TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
628
assert(STI && "Unable to create subtarget info");
629
630
MCSymbol *HwasanTagMismatchV1Sym =
631
OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
632
MCSymbol *HwasanTagMismatchV2Sym =
633
OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
634
635
const MCSymbolRefExpr *HwasanTagMismatchV1Ref =
636
MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext);
637
const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
638
MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
639
640
for (auto &P : HwasanMemaccessSymbols) {
641
unsigned Reg = std::get<0>(P.first);
642
bool IsShort = std::get<1>(P.first);
643
uint32_t AccessInfo = std::get<2>(P.first);
644
bool IsFixedShadow = std::get<3>(P.first);
645
uint64_t FixedShadowOffset = std::get<4>(P.first);
646
const MCSymbolRefExpr *HwasanTagMismatchRef =
647
IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
648
MCSymbol *Sym = P.second;
649
650
bool HasMatchAllTag =
651
(AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1;
652
uint8_t MatchAllTag =
653
(AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff;
654
unsigned Size =
655
1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
656
bool CompileKernel =
657
(AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1;
658
659
OutStreamer->switchSection(OutContext.getELFSection(
660
".text.hot", ELF::SHT_PROGBITS,
661
ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
662
/*IsComdat=*/true));
663
664
OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
665
OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
666
OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
667
OutStreamer->emitLabel(Sym);
668
669
OutStreamer->emitInstruction(MCInstBuilder(AArch64::SBFMXri)
670
.addReg(AArch64::X16)
671
.addReg(Reg)
672
.addImm(4)
673
.addImm(55),
674
*STI);
675
676
if (IsFixedShadow) {
677
// Aarch64 makes it difficult to embed large constants in the code.
678
// Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit
679
// left-shift option in the MOV instruction. Combined with the 16-bit
680
// immediate, this is enough to represent any offset up to 2**48.
681
OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
682
.addReg(AArch64::X17)
683
.addImm(FixedShadowOffset >> 32)
684
.addImm(32),
685
*STI);
686
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX)
687
.addReg(AArch64::W16)
688
.addReg(AArch64::X17)
689
.addReg(AArch64::X16)
690
.addImm(0)
691
.addImm(0),
692
*STI);
693
} else {
694
OutStreamer->emitInstruction(
695
MCInstBuilder(AArch64::LDRBBroX)
696
.addReg(AArch64::W16)
697
.addReg(IsShort ? AArch64::X20 : AArch64::X9)
698
.addReg(AArch64::X16)
699
.addImm(0)
700
.addImm(0),
701
*STI);
702
}
703
704
OutStreamer->emitInstruction(
705
MCInstBuilder(AArch64::SUBSXrs)
706
.addReg(AArch64::XZR)
707
.addReg(AArch64::X16)
708
.addReg(Reg)
709
.addImm(AArch64_AM::getShifterImm(AArch64_AM::LSR, 56)),
710
*STI);
711
MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
712
OutStreamer->emitInstruction(
713
MCInstBuilder(AArch64::Bcc)
714
.addImm(AArch64CC::NE)
715
.addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
716
OutContext)),
717
*STI);
718
MCSymbol *ReturnSym = OutContext.createTempSymbol();
719
OutStreamer->emitLabel(ReturnSym);
720
OutStreamer->emitInstruction(
721
MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
722
OutStreamer->emitLabel(HandleMismatchOrPartialSym);
723
724
if (HasMatchAllTag) {
725
OutStreamer->emitInstruction(MCInstBuilder(AArch64::UBFMXri)
726
.addReg(AArch64::X17)
727
.addReg(Reg)
728
.addImm(56)
729
.addImm(63),
730
*STI);
731
OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSXri)
732
.addReg(AArch64::XZR)
733
.addReg(AArch64::X17)
734
.addImm(MatchAllTag)
735
.addImm(0),
736
*STI);
737
OutStreamer->emitInstruction(
738
MCInstBuilder(AArch64::Bcc)
739
.addImm(AArch64CC::EQ)
740
.addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
741
*STI);
742
}
743
744
if (IsShort) {
745
OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWri)
746
.addReg(AArch64::WZR)
747
.addReg(AArch64::W16)
748
.addImm(15)
749
.addImm(0),
750
*STI);
751
MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
752
OutStreamer->emitInstruction(
753
MCInstBuilder(AArch64::Bcc)
754
.addImm(AArch64CC::HI)
755
.addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
756
*STI);
757
758
OutStreamer->emitInstruction(
759
MCInstBuilder(AArch64::ANDXri)
760
.addReg(AArch64::X17)
761
.addReg(Reg)
762
.addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)),
763
*STI);
764
if (Size != 1)
765
OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
766
.addReg(AArch64::X17)
767
.addReg(AArch64::X17)
768
.addImm(Size - 1)
769
.addImm(0),
770
*STI);
771
OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWrs)
772
.addReg(AArch64::WZR)
773
.addReg(AArch64::W16)
774
.addReg(AArch64::W17)
775
.addImm(0),
776
*STI);
777
OutStreamer->emitInstruction(
778
MCInstBuilder(AArch64::Bcc)
779
.addImm(AArch64CC::LS)
780
.addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
781
*STI);
782
783
OutStreamer->emitInstruction(
784
MCInstBuilder(AArch64::ORRXri)
785
.addReg(AArch64::X16)
786
.addReg(Reg)
787
.addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)),
788
*STI);
789
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBui)
790
.addReg(AArch64::W16)
791
.addReg(AArch64::X16)
792
.addImm(0),
793
*STI);
794
OutStreamer->emitInstruction(
795
MCInstBuilder(AArch64::SUBSXrs)
796
.addReg(AArch64::XZR)
797
.addReg(AArch64::X16)
798
.addReg(Reg)
799
.addImm(AArch64_AM::getShifterImm(AArch64_AM::LSR, 56)),
800
*STI);
801
OutStreamer->emitInstruction(
802
MCInstBuilder(AArch64::Bcc)
803
.addImm(AArch64CC::EQ)
804
.addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
805
*STI);
806
807
OutStreamer->emitLabel(HandleMismatchSym);
808
}
809
810
OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
811
.addReg(AArch64::SP)
812
.addReg(AArch64::X0)
813
.addReg(AArch64::X1)
814
.addReg(AArch64::SP)
815
.addImm(-32),
816
*STI);
817
OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
818
.addReg(AArch64::FP)
819
.addReg(AArch64::LR)
820
.addReg(AArch64::SP)
821
.addImm(29),
822
*STI);
823
824
if (Reg != AArch64::X0)
825
OutStreamer->emitInstruction(MCInstBuilder(AArch64::ORRXrs)
826
.addReg(AArch64::X0)
827
.addReg(AArch64::XZR)
828
.addReg(Reg)
829
.addImm(0),
830
*STI);
831
OutStreamer->emitInstruction(
832
MCInstBuilder(AArch64::MOVZXi)
833
.addReg(AArch64::X1)
834
.addImm(AccessInfo & HWASanAccessInfo::RuntimeMask)
835
.addImm(0),
836
*STI);
837
838
if (CompileKernel) {
839
// The Linux kernel's dynamic loader doesn't support GOT relative
840
// relocations, but it doesn't support late binding either, so just call
841
// the function directly.
842
OutStreamer->emitInstruction(
843
MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef), *STI);
844
} else {
845
// Intentionally load the GOT entry and branch to it, rather than possibly
846
// late binding the function, which may clobber the registers before we
847
// have a chance to save them.
848
OutStreamer->emitInstruction(
849
MCInstBuilder(AArch64::ADRP)
850
.addReg(AArch64::X16)
851
.addExpr(AArch64MCExpr::create(
852
HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_PAGE,
853
OutContext)),
854
*STI);
855
OutStreamer->emitInstruction(
856
MCInstBuilder(AArch64::LDRXui)
857
.addReg(AArch64::X16)
858
.addReg(AArch64::X16)
859
.addExpr(AArch64MCExpr::create(
860
HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_LO12,
861
OutContext)),
862
*STI);
863
OutStreamer->emitInstruction(
864
MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI);
865
}
866
}
867
}
868
869
static void emitAuthenticatedPointer(MCStreamer &OutStreamer,
870
MCSymbol *StubLabel,
871
const MCExpr *StubAuthPtrRef) {
872
// sym$auth_ptr$key$disc:
873
OutStreamer.emitLabel(StubLabel);
874
OutStreamer.emitValue(StubAuthPtrRef, /*size=*/8);
875
}
876
877
void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
878
emitHwasanMemaccessSymbols(M);
879
880
const Triple &TT = TM.getTargetTriple();
881
if (TT.isOSBinFormatMachO()) {
882
// Output authenticated pointers as indirect symbols, if we have any.
883
MachineModuleInfoMachO &MMIMacho =
884
MMI->getObjFileInfo<MachineModuleInfoMachO>();
885
886
auto Stubs = MMIMacho.getAuthGVStubList();
887
888
if (!Stubs.empty()) {
889
// Switch to the "__auth_ptr" section.
890
OutStreamer->switchSection(
891
OutContext.getMachOSection("__DATA", "__auth_ptr", MachO::S_REGULAR,
892
SectionKind::getMetadata()));
893
emitAlignment(Align(8));
894
895
for (const auto &Stub : Stubs)
896
emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
897
898
OutStreamer->addBlankLine();
899
}
900
901
// Funny Darwin hack: This flag tells the linker that no global symbols
902
// contain code that falls through to other global symbols (e.g. the obvious
903
// implementation of multiple entry points). If this doesn't occur, the
904
// linker can safely perform dead code stripping. Since LLVM never
905
// generates code that does this, it is always safe to set.
906
OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols);
907
}
908
909
if (TT.isOSBinFormatELF()) {
910
// Output authenticated pointers as indirect symbols, if we have any.
911
MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
912
913
auto Stubs = MMIELF.getAuthGVStubList();
914
915
if (!Stubs.empty()) {
916
const TargetLoweringObjectFile &TLOF = getObjFileLowering();
917
OutStreamer->switchSection(TLOF.getDataSection());
918
emitAlignment(Align(8));
919
920
for (const auto &Stub : Stubs)
921
emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
922
923
OutStreamer->addBlankLine();
924
}
925
}
926
927
// Emit stack and fault map information.
928
FM.serializeToFaultMapSection();
929
930
}
931
932
void AArch64AsmPrinter::emitLOHs() {
933
SmallVector<MCSymbol *, 3> MCArgs;
934
935
for (const auto &D : AArch64FI->getLOHContainer()) {
936
for (const MachineInstr *MI : D.getArgs()) {
937
MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
938
assert(LabelIt != LOHInstToLabel.end() &&
939
"Label hasn't been inserted for LOH related instruction");
940
MCArgs.push_back(LabelIt->second);
941
}
942
OutStreamer->emitLOHDirective(D.getKind(), MCArgs);
943
MCArgs.clear();
944
}
945
}
946
947
void AArch64AsmPrinter::emitFunctionBodyEnd() {
948
if (!AArch64FI->getLOHRelated().empty())
949
emitLOHs();
950
}
951
952
/// GetCPISymbol - Return the symbol for the specified constant pool entry.
953
MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
954
// Darwin uses a linker-private symbol name for constant-pools (to
955
// avoid addends on the relocation?), ELF has no such concept and
956
// uses a normal private symbol.
957
if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
958
return OutContext.getOrCreateSymbol(
959
Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
960
Twine(getFunctionNumber()) + "_" + Twine(CPID));
961
962
return AsmPrinter::GetCPISymbol(CPID);
963
}
964
965
void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
966
raw_ostream &O) {
967
const MachineOperand &MO = MI->getOperand(OpNum);
968
switch (MO.getType()) {
969
default:
970
llvm_unreachable("<unknown operand type>");
971
case MachineOperand::MO_Register: {
972
Register Reg = MO.getReg();
973
assert(Reg.isPhysical());
974
assert(!MO.getSubReg() && "Subregs should be eliminated!");
975
O << AArch64InstPrinter::getRegisterName(Reg);
976
break;
977
}
978
case MachineOperand::MO_Immediate: {
979
O << MO.getImm();
980
break;
981
}
982
case MachineOperand::MO_GlobalAddress: {
983
PrintSymbolOperand(MO, O);
984
break;
985
}
986
case MachineOperand::MO_BlockAddress: {
987
MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
988
Sym->print(O, MAI);
989
break;
990
}
991
}
992
}
993
994
bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
995
raw_ostream &O) {
996
Register Reg = MO.getReg();
997
switch (Mode) {
998
default:
999
return true; // Unknown mode.
1000
case 'w':
1001
Reg = getWRegFromXReg(Reg);
1002
break;
1003
case 'x':
1004
Reg = getXRegFromWReg(Reg);
1005
break;
1006
case 't':
1007
Reg = getXRegFromXRegTuple(Reg);
1008
break;
1009
}
1010
1011
O << AArch64InstPrinter::getRegisterName(Reg);
1012
return false;
1013
}
1014
1015
// Prints the register in MO using class RC using the offset in the
1016
// new register class. This should not be used for cross class
1017
// printing.
1018
bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
1019
const TargetRegisterClass *RC,
1020
unsigned AltName, raw_ostream &O) {
1021
assert(MO.isReg() && "Should only get here with a register!");
1022
const TargetRegisterInfo *RI = STI->getRegisterInfo();
1023
Register Reg = MO.getReg();
1024
unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
1025
if (!RI->regsOverlap(RegToPrint, Reg))
1026
return true;
1027
O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName);
1028
return false;
1029
}
1030
1031
bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
1032
const char *ExtraCode, raw_ostream &O) {
1033
const MachineOperand &MO = MI->getOperand(OpNum);
1034
1035
// First try the generic code, which knows about modifiers like 'c' and 'n'.
1036
if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
1037
return false;
1038
1039
// Does this asm operand have a single letter operand modifier?
1040
if (ExtraCode && ExtraCode[0]) {
1041
if (ExtraCode[1] != 0)
1042
return true; // Unknown modifier.
1043
1044
switch (ExtraCode[0]) {
1045
default:
1046
return true; // Unknown modifier.
1047
case 'w': // Print W register
1048
case 'x': // Print X register
1049
if (MO.isReg())
1050
return printAsmMRegister(MO, ExtraCode[0], O);
1051
if (MO.isImm() && MO.getImm() == 0) {
1052
unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
1053
O << AArch64InstPrinter::getRegisterName(Reg);
1054
return false;
1055
}
1056
printOperand(MI, OpNum, O);
1057
return false;
1058
case 'b': // Print B register.
1059
case 'h': // Print H register.
1060
case 's': // Print S register.
1061
case 'd': // Print D register.
1062
case 'q': // Print Q register.
1063
case 'z': // Print Z register.
1064
if (MO.isReg()) {
1065
const TargetRegisterClass *RC;
1066
switch (ExtraCode[0]) {
1067
case 'b':
1068
RC = &AArch64::FPR8RegClass;
1069
break;
1070
case 'h':
1071
RC = &AArch64::FPR16RegClass;
1072
break;
1073
case 's':
1074
RC = &AArch64::FPR32RegClass;
1075
break;
1076
case 'd':
1077
RC = &AArch64::FPR64RegClass;
1078
break;
1079
case 'q':
1080
RC = &AArch64::FPR128RegClass;
1081
break;
1082
case 'z':
1083
RC = &AArch64::ZPRRegClass;
1084
break;
1085
default:
1086
return true;
1087
}
1088
return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
1089
}
1090
printOperand(MI, OpNum, O);
1091
return false;
1092
}
1093
}
1094
1095
// According to ARM, we should emit x and v registers unless we have a
1096
// modifier.
1097
if (MO.isReg()) {
1098
Register Reg = MO.getReg();
1099
1100
// If this is a w or x register, print an x register.
1101
if (AArch64::GPR32allRegClass.contains(Reg) ||
1102
AArch64::GPR64allRegClass.contains(Reg))
1103
return printAsmMRegister(MO, 'x', O);
1104
1105
// If this is an x register tuple, print an x register.
1106
if (AArch64::GPR64x8ClassRegClass.contains(Reg))
1107
return printAsmMRegister(MO, 't', O);
1108
1109
unsigned AltName = AArch64::NoRegAltName;
1110
const TargetRegisterClass *RegClass;
1111
if (AArch64::ZPRRegClass.contains(Reg)) {
1112
RegClass = &AArch64::ZPRRegClass;
1113
} else if (AArch64::PPRRegClass.contains(Reg)) {
1114
RegClass = &AArch64::PPRRegClass;
1115
} else if (AArch64::PNRRegClass.contains(Reg)) {
1116
RegClass = &AArch64::PNRRegClass;
1117
} else {
1118
RegClass = &AArch64::FPR128RegClass;
1119
AltName = AArch64::vreg;
1120
}
1121
1122
// If this is a b, h, s, d, or q register, print it as a v register.
1123
return printAsmRegInClass(MO, RegClass, AltName, O);
1124
}
1125
1126
printOperand(MI, OpNum, O);
1127
return false;
1128
}
1129
1130
bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1131
unsigned OpNum,
1132
const char *ExtraCode,
1133
raw_ostream &O) {
1134
if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
1135
return true; // Unknown modifier.
1136
1137
const MachineOperand &MO = MI->getOperand(OpNum);
1138
assert(MO.isReg() && "unexpected inline asm memory operand");
1139
O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
1140
return false;
1141
}
1142
1143
void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
1144
raw_ostream &OS) {
1145
unsigned NOps = MI->getNumOperands();
1146
assert(NOps == 4);
1147
OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
1148
// cast away const; DIetc do not take const operands for some reason.
1149
OS << MI->getDebugVariable()->getName();
1150
OS << " <- ";
1151
// Frame address. Currently handles register +- offset only.
1152
assert(MI->isIndirectDebugValue());
1153
OS << '[';
1154
for (unsigned I = 0, E = std::distance(MI->debug_operands().begin(),
1155
MI->debug_operands().end());
1156
I < E; ++I) {
1157
if (I != 0)
1158
OS << ", ";
1159
printOperand(MI, I, OS);
1160
}
1161
OS << ']';
1162
OS << "+";
1163
printOperand(MI, NOps - 2, OS);
1164
}
1165
1166
void AArch64AsmPrinter::emitJumpTableInfo() {
1167
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
1168
if (!MJTI) return;
1169
1170
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
1171
if (JT.empty()) return;
1172
1173
const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1174
MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(MF->getFunction(), TM);
1175
OutStreamer->switchSection(ReadOnlySec);
1176
1177
auto AFI = MF->getInfo<AArch64FunctionInfo>();
1178
for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
1179
const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
1180
1181
// If this jump table was deleted, ignore it.
1182
if (JTBBs.empty()) continue;
1183
1184
unsigned Size = AFI->getJumpTableEntrySize(JTI);
1185
emitAlignment(Align(Size));
1186
OutStreamer->emitLabel(GetJTISymbol(JTI));
1187
1188
const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1189
const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
1190
1191
for (auto *JTBB : JTBBs) {
1192
const MCExpr *Value =
1193
MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext);
1194
1195
// Each entry is:
1196
// .byte/.hword (LBB - Lbase)>>2
1197
// or plain:
1198
// .word LBB - Lbase
1199
Value = MCBinaryExpr::createSub(Value, Base, OutContext);
1200
if (Size != 4)
1201
Value = MCBinaryExpr::createLShr(
1202
Value, MCConstantExpr::create(2, OutContext), OutContext);
1203
1204
OutStreamer->emitValue(Value, Size);
1205
}
1206
}
1207
}
1208
1209
std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
1210
codeview::JumpTableEntrySize>
1211
AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI,
1212
const MachineInstr *BranchInstr,
1213
const MCSymbol *BranchLabel) const {
1214
const auto AFI = MF->getInfo<AArch64FunctionInfo>();
1215
const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1216
codeview::JumpTableEntrySize EntrySize;
1217
switch (AFI->getJumpTableEntrySize(JTI)) {
1218
case 1:
1219
EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
1220
break;
1221
case 2:
1222
EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
1223
break;
1224
case 4:
1225
EntrySize = codeview::JumpTableEntrySize::Int32;
1226
break;
1227
default:
1228
llvm_unreachable("Unexpected jump table entry size");
1229
}
1230
return std::make_tuple(Base, 0, BranchLabel, EntrySize);
1231
}
1232
1233
void AArch64AsmPrinter::emitFunctionEntryLabel() {
1234
if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
1235
MF->getFunction().getCallingConv() ==
1236
CallingConv::AArch64_SVE_VectorCall ||
1237
MF->getInfo<AArch64FunctionInfo>()->isSVECC()) {
1238
auto *TS =
1239
static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1240
TS->emitDirectiveVariantPCS(CurrentFnSym);
1241
}
1242
1243
AsmPrinter::emitFunctionEntryLabel();
1244
1245
if (TM.getTargetTriple().isWindowsArm64EC() &&
1246
!MF->getFunction().hasLocalLinkage()) {
1247
// For ARM64EC targets, a function definition's name is mangled differently
1248
// from the normal symbol, emit required aliases here.
1249
auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) {
1250
OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep);
1251
OutStreamer->emitAssignment(
1252
Src, MCSymbolRefExpr::create(Dst, MCSymbolRefExpr::VK_None,
1253
MMI->getContext()));
1254
};
1255
1256
auto getSymbolFromMetadata = [&](StringRef Name) {
1257
MCSymbol *Sym = nullptr;
1258
if (MDNode *Node = MF->getFunction().getMetadata(Name)) {
1259
StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1260
Sym = MMI->getContext().getOrCreateSymbol(NameStr);
1261
}
1262
return Sym;
1263
};
1264
1265
if (MCSymbol *UnmangledSym =
1266
getSymbolFromMetadata("arm64ec_unmangled_name")) {
1267
MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name");
1268
1269
if (ECMangledSym) {
1270
// An external function, emit the alias from the unmangled symbol to
1271
// mangled symbol name and the alias from the mangled symbol to guest
1272
// exit thunk.
1273
emitFunctionAlias(UnmangledSym, ECMangledSym);
1274
emitFunctionAlias(ECMangledSym, CurrentFnSym);
1275
} else {
1276
// A function implementation, emit the alias from the unmangled symbol
1277
// to mangled symbol name.
1278
emitFunctionAlias(UnmangledSym, CurrentFnSym);
1279
}
1280
}
1281
}
1282
}
1283
1284
void AArch64AsmPrinter::emitGlobalAlias(const Module &M,
1285
const GlobalAlias &GA) {
1286
if (auto F = dyn_cast_or_null<Function>(GA.getAliasee())) {
1287
// Global aliases must point to a definition, but unmangled patchable
1288
// symbols are special and need to point to an undefined symbol with "EXP+"
1289
// prefix. Such undefined symbol is resolved by the linker by creating
1290
// x86 thunk that jumps back to the actual EC target.
1291
if (MDNode *Node = F->getMetadata("arm64ec_exp_name")) {
1292
StringRef ExpStr = cast<MDString>(Node->getOperand(0))->getString();
1293
MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr);
1294
MCSymbol *Sym = MMI->getContext().getOrCreateSymbol(GA.getName());
1295
1296
OutStreamer->beginCOFFSymbolDef(ExpSym);
1297
OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1298
OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1299
<< COFF::SCT_COMPLEX_TYPE_SHIFT);
1300
OutStreamer->endCOFFSymbolDef();
1301
1302
OutStreamer->beginCOFFSymbolDef(Sym);
1303
OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1304
OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1305
<< COFF::SCT_COMPLEX_TYPE_SHIFT);
1306
OutStreamer->endCOFFSymbolDef();
1307
OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
1308
OutStreamer->emitAssignment(
1309
Sym, MCSymbolRefExpr::create(ExpSym, MCSymbolRefExpr::VK_None,
1310
MMI->getContext()));
1311
return;
1312
}
1313
}
1314
AsmPrinter::emitGlobalAlias(M, GA);
1315
}
1316
1317
/// Small jump tables contain an unsigned byte or half, representing the offset
1318
/// from the lowest-addressed possible destination to the desired basic
1319
/// block. Since all instructions are 4-byte aligned, this is further compressed
1320
/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
1321
/// materialize the correct destination we need:
1322
///
1323
/// adr xDest, .LBB0_0
1324
/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
1325
/// add xDest, xDest, xScratch (with "lsl #2" for smaller entries)
1326
void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer,
1327
const llvm::MachineInstr &MI) {
1328
Register DestReg = MI.getOperand(0).getReg();
1329
Register ScratchReg = MI.getOperand(1).getReg();
1330
Register ScratchRegW =
1331
STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
1332
Register TableReg = MI.getOperand(2).getReg();
1333
Register EntryReg = MI.getOperand(3).getReg();
1334
int JTIdx = MI.getOperand(4).getIndex();
1335
int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
1336
1337
// This has to be first because the compression pass based its reachability
1338
// calculations on the start of the JumpTableDest instruction.
1339
auto Label =
1340
MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
1341
1342
// If we don't already have a symbol to use as the base, use the ADR
1343
// instruction itself.
1344
if (!Label) {
1345
Label = MF->getContext().createTempSymbol();
1346
AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label);
1347
OutStreamer.emitLabel(Label);
1348
}
1349
1350
auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext());
1351
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
1352
.addReg(DestReg)
1353
.addExpr(LabelExpr));
1354
1355
// Load the number of instruction-steps to offset from the label.
1356
unsigned LdrOpcode;
1357
switch (Size) {
1358
case 1: LdrOpcode = AArch64::LDRBBroX; break;
1359
case 2: LdrOpcode = AArch64::LDRHHroX; break;
1360
case 4: LdrOpcode = AArch64::LDRSWroX; break;
1361
default:
1362
llvm_unreachable("Unknown jump table size");
1363
}
1364
1365
EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
1366
.addReg(Size == 4 ? ScratchReg : ScratchRegW)
1367
.addReg(TableReg)
1368
.addReg(EntryReg)
1369
.addImm(0)
1370
.addImm(Size == 1 ? 0 : 1));
1371
1372
// Add to the already materialized base label address, multiplying by 4 if
1373
// compressed.
1374
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1375
.addReg(DestReg)
1376
.addReg(DestReg)
1377
.addReg(ScratchReg)
1378
.addImm(Size == 4 ? 0 : 2));
1379
}
1380
1381
void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) {
1382
unsigned InstsEmitted = 0;
1383
1384
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
1385
assert(MJTI && "Can't lower jump-table dispatch without JTI");
1386
1387
const std::vector<MachineJumpTableEntry> &JTs = MJTI->getJumpTables();
1388
assert(!JTs.empty() && "Invalid JT index for jump-table dispatch");
1389
1390
// Emit:
1391
// mov x17, #<size of table> ; depending on table size, with MOVKs
1392
// cmp x16, x17 ; or #imm if table size fits in 12-bit
1393
// csel x16, x16, xzr, ls ; check for index overflow
1394
//
1395
// adrp x17, Ltable@PAGE ; materialize table address
1396
// add x17, Ltable@PAGEOFF
1397
// ldrsw x16, [x17, x16, lsl #2] ; load table entry
1398
//
1399
// Lanchor:
1400
// adr x17, Lanchor ; compute target address
1401
// add x16, x17, x16
1402
// br x16 ; branch to target
1403
1404
MachineOperand JTOp = MI.getOperand(0);
1405
1406
unsigned JTI = JTOp.getIndex();
1407
assert(!AArch64FI->getJumpTableEntryPCRelSymbol(JTI) &&
1408
"unsupported compressed jump table");
1409
1410
const uint64_t NumTableEntries = JTs[JTI].MBBs.size();
1411
1412
// cmp only supports a 12-bit immediate. If we need more, materialize the
1413
// immediate, using x17 as a scratch register.
1414
uint64_t MaxTableEntry = NumTableEntries - 1;
1415
if (isUInt<12>(MaxTableEntry)) {
1416
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXri)
1417
.addReg(AArch64::XZR)
1418
.addReg(AArch64::X16)
1419
.addImm(MaxTableEntry)
1420
.addImm(0));
1421
++InstsEmitted;
1422
} else {
1423
EmitToStreamer(*OutStreamer,
1424
MCInstBuilder(AArch64::MOVZXi)
1425
.addReg(AArch64::X17)
1426
.addImm(static_cast<uint16_t>(MaxTableEntry))
1427
.addImm(0));
1428
++InstsEmitted;
1429
// It's sad that we have to manually materialize instructions, but we can't
1430
// trivially reuse the main pseudo expansion logic.
1431
// A MOVK sequence is easy enough to generate and handles the general case.
1432
for (int Offset = 16; Offset < 64; Offset += 16) {
1433
if ((MaxTableEntry >> Offset) == 0)
1434
break;
1435
EmitToStreamer(*OutStreamer,
1436
MCInstBuilder(AArch64::MOVKXi)
1437
.addReg(AArch64::X17)
1438
.addReg(AArch64::X17)
1439
.addImm(static_cast<uint16_t>(MaxTableEntry >> Offset))
1440
.addImm(Offset));
1441
++InstsEmitted;
1442
}
1443
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs)
1444
.addReg(AArch64::XZR)
1445
.addReg(AArch64::X16)
1446
.addReg(AArch64::X17)
1447
.addImm(0));
1448
++InstsEmitted;
1449
}
1450
1451
// This picks entry #0 on failure.
1452
// We might want to trap instead.
1453
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CSELXr)
1454
.addReg(AArch64::X16)
1455
.addReg(AArch64::X16)
1456
.addReg(AArch64::XZR)
1457
.addImm(AArch64CC::LS));
1458
++InstsEmitted;
1459
1460
// Prepare the @PAGE/@PAGEOFF low/high operands.
1461
MachineOperand JTMOHi(JTOp), JTMOLo(JTOp);
1462
MCOperand JTMCHi, JTMCLo;
1463
1464
JTMOHi.setTargetFlags(AArch64II::MO_PAGE);
1465
JTMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
1466
1467
MCInstLowering.lowerOperand(JTMOHi, JTMCHi);
1468
MCInstLowering.lowerOperand(JTMOLo, JTMCLo);
1469
1470
EmitToStreamer(
1471
*OutStreamer,
1472
MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(JTMCHi));
1473
++InstsEmitted;
1474
1475
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri)
1476
.addReg(AArch64::X17)
1477
.addReg(AArch64::X17)
1478
.addOperand(JTMCLo)
1479
.addImm(0));
1480
++InstsEmitted;
1481
1482
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX)
1483
.addReg(AArch64::X16)
1484
.addReg(AArch64::X17)
1485
.addReg(AArch64::X16)
1486
.addImm(0)
1487
.addImm(1));
1488
++InstsEmitted;
1489
1490
MCSymbol *AdrLabel = MF->getContext().createTempSymbol();
1491
const auto *AdrLabelE = MCSymbolRefExpr::create(AdrLabel, MF->getContext());
1492
AArch64FI->setJumpTableEntryInfo(JTI, 4, AdrLabel);
1493
1494
OutStreamer->emitLabel(AdrLabel);
1495
EmitToStreamer(
1496
*OutStreamer,
1497
MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addExpr(AdrLabelE));
1498
++InstsEmitted;
1499
1500
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1501
.addReg(AArch64::X16)
1502
.addReg(AArch64::X17)
1503
.addReg(AArch64::X16)
1504
.addImm(0));
1505
++InstsEmitted;
1506
1507
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
1508
++InstsEmitted;
1509
1510
(void)InstsEmitted;
1511
assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4);
1512
}
1513
1514
void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer,
1515
const llvm::MachineInstr &MI) {
1516
unsigned Opcode = MI.getOpcode();
1517
assert(STI->hasMOPS());
1518
assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
1519
1520
const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
1521
if (Opcode == AArch64::MOPSMemoryCopyPseudo)
1522
return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
1523
if (Opcode == AArch64::MOPSMemoryMovePseudo)
1524
return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
1525
if (Opcode == AArch64::MOPSMemorySetPseudo)
1526
return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
1527
if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
1528
return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
1529
llvm_unreachable("Unhandled memory operation pseudo");
1530
}();
1531
const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
1532
Opcode == AArch64::MOPSMemorySetTaggingPseudo;
1533
1534
for (auto Op : Ops) {
1535
int i = 0;
1536
auto MCIB = MCInstBuilder(Op);
1537
// Destination registers
1538
MCIB.addReg(MI.getOperand(i++).getReg());
1539
MCIB.addReg(MI.getOperand(i++).getReg());
1540
if (!IsSet)
1541
MCIB.addReg(MI.getOperand(i++).getReg());
1542
// Input registers
1543
MCIB.addReg(MI.getOperand(i++).getReg());
1544
MCIB.addReg(MI.getOperand(i++).getReg());
1545
MCIB.addReg(MI.getOperand(i++).getReg());
1546
1547
EmitToStreamer(OutStreamer, MCIB);
1548
}
1549
}
1550
1551
void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1552
const MachineInstr &MI) {
1553
unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
1554
1555
auto &Ctx = OutStreamer.getContext();
1556
MCSymbol *MILabel = Ctx.createTempSymbol();
1557
OutStreamer.emitLabel(MILabel);
1558
1559
SM.recordStackMap(*MILabel, MI);
1560
assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1561
1562
// Scan ahead to trim the shadow.
1563
const MachineBasicBlock &MBB = *MI.getParent();
1564
MachineBasicBlock::const_iterator MII(MI);
1565
++MII;
1566
while (NumNOPBytes > 0) {
1567
if (MII == MBB.end() || MII->isCall() ||
1568
MII->getOpcode() == AArch64::DBG_VALUE ||
1569
MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1570
MII->getOpcode() == TargetOpcode::STACKMAP)
1571
break;
1572
++MII;
1573
NumNOPBytes -= 4;
1574
}
1575
1576
// Emit nops.
1577
for (unsigned i = 0; i < NumNOPBytes; i += 4)
1578
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1579
}
1580
1581
// Lower a patchpoint of the form:
1582
// [<def>], <id>, <numBytes>, <target>, <numArgs>
1583
void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1584
const MachineInstr &MI) {
1585
auto &Ctx = OutStreamer.getContext();
1586
MCSymbol *MILabel = Ctx.createTempSymbol();
1587
OutStreamer.emitLabel(MILabel);
1588
SM.recordPatchPoint(*MILabel, MI);
1589
1590
PatchPointOpers Opers(&MI);
1591
1592
int64_t CallTarget = Opers.getCallTarget().getImm();
1593
unsigned EncodedBytes = 0;
1594
if (CallTarget) {
1595
assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
1596
"High 16 bits of call target should be zero.");
1597
Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
1598
EncodedBytes = 16;
1599
// Materialize the jump address:
1600
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1601
.addReg(ScratchReg)
1602
.addImm((CallTarget >> 32) & 0xFFFF)
1603
.addImm(32));
1604
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1605
.addReg(ScratchReg)
1606
.addReg(ScratchReg)
1607
.addImm((CallTarget >> 16) & 0xFFFF)
1608
.addImm(16));
1609
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1610
.addReg(ScratchReg)
1611
.addReg(ScratchReg)
1612
.addImm(CallTarget & 0xFFFF)
1613
.addImm(0));
1614
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
1615
}
1616
// Emit padding.
1617
unsigned NumBytes = Opers.getNumPatchBytes();
1618
assert(NumBytes >= EncodedBytes &&
1619
"Patchpoint can't request size less than the length of a call.");
1620
assert((NumBytes - EncodedBytes) % 4 == 0 &&
1621
"Invalid number of NOP bytes requested!");
1622
for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
1623
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1624
}
1625
1626
void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1627
const MachineInstr &MI) {
1628
StatepointOpers SOpers(&MI);
1629
if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1630
assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1631
for (unsigned i = 0; i < PatchBytes; i += 4)
1632
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1633
} else {
1634
// Lower call target and choose correct opcode
1635
const MachineOperand &CallTarget = SOpers.getCallTarget();
1636
MCOperand CallTargetMCOp;
1637
unsigned CallOpcode;
1638
switch (CallTarget.getType()) {
1639
case MachineOperand::MO_GlobalAddress:
1640
case MachineOperand::MO_ExternalSymbol:
1641
MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1642
CallOpcode = AArch64::BL;
1643
break;
1644
case MachineOperand::MO_Immediate:
1645
CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
1646
CallOpcode = AArch64::BL;
1647
break;
1648
case MachineOperand::MO_Register:
1649
CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
1650
CallOpcode = AArch64::BLR;
1651
break;
1652
default:
1653
llvm_unreachable("Unsupported operand type in statepoint call target");
1654
break;
1655
}
1656
1657
EmitToStreamer(OutStreamer,
1658
MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
1659
}
1660
1661
auto &Ctx = OutStreamer.getContext();
1662
MCSymbol *MILabel = Ctx.createTempSymbol();
1663
OutStreamer.emitLabel(MILabel);
1664
SM.recordStatepoint(*MILabel, MI);
1665
}
1666
1667
void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) {
1668
// FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>,
1669
// <opcode>, <operands>
1670
1671
Register DefRegister = FaultingMI.getOperand(0).getReg();
1672
FaultMaps::FaultKind FK =
1673
static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm());
1674
MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol();
1675
unsigned Opcode = FaultingMI.getOperand(3).getImm();
1676
unsigned OperandsBeginIdx = 4;
1677
1678
auto &Ctx = OutStreamer->getContext();
1679
MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1680
OutStreamer->emitLabel(FaultingLabel);
1681
1682
assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!");
1683
FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1684
1685
MCInst MI;
1686
MI.setOpcode(Opcode);
1687
1688
if (DefRegister != (Register)0)
1689
MI.addOperand(MCOperand::createReg(DefRegister));
1690
1691
for (const MachineOperand &MO :
1692
llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) {
1693
MCOperand Dest;
1694
lowerOperand(MO, Dest);
1695
MI.addOperand(Dest);
1696
}
1697
1698
OutStreamer->AddComment("on-fault: " + HandlerLabel->getName());
1699
OutStreamer->emitInstruction(MI, getSubtargetInfo());
1700
}
1701
1702
void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
1703
Register DestReg = MI.getOperand(0).getReg();
1704
if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() &&
1705
STI->isNeonAvailable()) {
1706
// Convert H/S register to corresponding D register
1707
if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
1708
DestReg = AArch64::D0 + (DestReg - AArch64::H0);
1709
else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
1710
DestReg = AArch64::D0 + (DestReg - AArch64::S0);
1711
else
1712
assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
1713
1714
MCInst MOVI;
1715
MOVI.setOpcode(AArch64::MOVID);
1716
MOVI.addOperand(MCOperand::createReg(DestReg));
1717
MOVI.addOperand(MCOperand::createImm(0));
1718
EmitToStreamer(*OutStreamer, MOVI);
1719
} else {
1720
MCInst FMov;
1721
switch (MI.getOpcode()) {
1722
default: llvm_unreachable("Unexpected opcode");
1723
case AArch64::FMOVH0:
1724
FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
1725
if (!STI->hasFullFP16())
1726
DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
1727
FMov.addOperand(MCOperand::createReg(DestReg));
1728
FMov.addOperand(MCOperand::createReg(AArch64::WZR));
1729
break;
1730
case AArch64::FMOVS0:
1731
FMov.setOpcode(AArch64::FMOVWSr);
1732
FMov.addOperand(MCOperand::createReg(DestReg));
1733
FMov.addOperand(MCOperand::createReg(AArch64::WZR));
1734
break;
1735
case AArch64::FMOVD0:
1736
FMov.setOpcode(AArch64::FMOVXDr);
1737
FMov.addOperand(MCOperand::createReg(DestReg));
1738
FMov.addOperand(MCOperand::createReg(AArch64::XZR));
1739
break;
1740
}
1741
EmitToStreamer(*OutStreamer, FMov);
1742
}
1743
}
1744
1745
unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
1746
unsigned AddrDisc,
1747
unsigned &InstsEmitted) {
1748
// So far we've used NoRegister in pseudos. Now we need real encodings.
1749
if (AddrDisc == AArch64::NoRegister)
1750
AddrDisc = AArch64::XZR;
1751
1752
// If there is no constant discriminator, there's no blend involved:
1753
// just use the address discriminator register as-is (XZR or not).
1754
if (!Disc)
1755
return AddrDisc;
1756
1757
// If there's only a constant discriminator, MOV it into x17.
1758
if (AddrDisc == AArch64::XZR) {
1759
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1760
.addReg(AArch64::X17)
1761
.addImm(Disc)
1762
.addImm(/*shift=*/0));
1763
++InstsEmitted;
1764
return AArch64::X17;
1765
}
1766
1767
// If there are both, emit a blend into x17.
1768
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1769
.addReg(AArch64::X17)
1770
.addReg(AArch64::XZR)
1771
.addReg(AddrDisc)
1772
.addImm(0));
1773
++InstsEmitted;
1774
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1775
.addReg(AArch64::X17)
1776
.addReg(AArch64::X17)
1777
.addImm(Disc)
1778
.addImm(/*shift=*/48));
1779
++InstsEmitted;
1780
return AArch64::X17;
1781
}
1782
1783
void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
1784
unsigned InstsEmitted = 0;
1785
const bool IsAUTPAC = MI->getOpcode() == AArch64::AUTPAC;
1786
1787
// We can expand AUT/AUTPAC into 3 possible sequences:
1788
// - unchecked:
1789
// autia x16, x0
1790
// pacib x16, x1 ; if AUTPAC
1791
//
1792
// - checked and clearing:
1793
// mov x17, x0
1794
// movk x17, #disc, lsl #48
1795
// autia x16, x17
1796
// mov x17, x16
1797
// xpaci x17
1798
// cmp x16, x17
1799
// b.eq Lsuccess
1800
// mov x16, x17
1801
// b Lend
1802
// Lsuccess:
1803
// mov x17, x1
1804
// movk x17, #disc, lsl #48
1805
// pacib x16, x17
1806
// Lend:
1807
// Where we only emit the AUT if we started with an AUT.
1808
//
1809
// - checked and trapping:
1810
// mov x17, x0
1811
// movk x17, #disc, lsl #48
1812
// autia x16, x0
1813
// mov x17, x16
1814
// xpaci x17
1815
// cmp x16, x17
1816
// b.eq Lsuccess
1817
// brk #<0xc470 + aut key>
1818
// Lsuccess:
1819
// mov x17, x1
1820
// movk x17, #disc, lsl #48
1821
// pacib x16, x17 ; if AUTPAC
1822
// Where the b.eq skips over the trap if the PAC is valid.
1823
//
1824
// This sequence is expensive, but we need more information to be able to
1825
// do better.
1826
//
1827
// We can't TBZ the poison bit because EnhancedPAC2 XORs the PAC bits
1828
// on failure.
1829
// We can't TST the PAC bits because we don't always know how the address
1830
// space is setup for the target environment (and the bottom PAC bit is
1831
// based on that).
1832
// Either way, we also don't always know whether TBI is enabled or not for
1833
// the specific target environment.
1834
1835
// By default, auth/resign sequences check for auth failures.
1836
bool ShouldCheck = true;
1837
// In the checked sequence, we only trap if explicitly requested.
1838
bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps");
1839
1840
// On an FPAC CPU, you get traps whether you want them or not: there's
1841
// no point in emitting checks or traps.
1842
if (STI->hasFPAC())
1843
ShouldCheck = ShouldTrap = false;
1844
1845
// However, command-line flags can override this, for experimentation.
1846
switch (PtrauthAuthChecks) {
1847
case PtrauthCheckMode::Default:
1848
break;
1849
case PtrauthCheckMode::Unchecked:
1850
ShouldCheck = ShouldTrap = false;
1851
break;
1852
case PtrauthCheckMode::Poison:
1853
ShouldCheck = true;
1854
ShouldTrap = false;
1855
break;
1856
case PtrauthCheckMode::Trap:
1857
ShouldCheck = ShouldTrap = true;
1858
break;
1859
}
1860
1861
auto AUTKey = (AArch64PACKey::ID)MI->getOperand(0).getImm();
1862
uint64_t AUTDisc = MI->getOperand(1).getImm();
1863
unsigned AUTAddrDisc = MI->getOperand(2).getReg();
1864
1865
unsigned XPACOpc = getXPACOpcodeForKey(AUTKey);
1866
1867
// Compute aut discriminator into x17
1868
assert(isUInt<16>(AUTDisc));
1869
unsigned AUTDiscReg =
1870
emitPtrauthDiscriminator(AUTDisc, AUTAddrDisc, InstsEmitted);
1871
bool AUTZero = AUTDiscReg == AArch64::XZR;
1872
unsigned AUTOpc = getAUTOpcodeForKey(AUTKey, AUTZero);
1873
1874
// autiza x16 ; if AUTZero
1875
// autia x16, x17 ; if !AUTZero
1876
MCInst AUTInst;
1877
AUTInst.setOpcode(AUTOpc);
1878
AUTInst.addOperand(MCOperand::createReg(AArch64::X16));
1879
AUTInst.addOperand(MCOperand::createReg(AArch64::X16));
1880
if (!AUTZero)
1881
AUTInst.addOperand(MCOperand::createReg(AUTDiscReg));
1882
EmitToStreamer(*OutStreamer, AUTInst);
1883
++InstsEmitted;
1884
1885
// Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done.
1886
if (!IsAUTPAC && (!ShouldCheck || !ShouldTrap)) {
1887
assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
1888
return;
1889
}
1890
1891
MCSymbol *EndSym = nullptr;
1892
1893
// Checked sequences do an additional strip-and-compare.
1894
if (ShouldCheck) {
1895
MCSymbol *SuccessSym = createTempSymbol("auth_success_");
1896
1897
// XPAC has tied src/dst: use x17 as a temporary copy.
1898
// mov x17, x16
1899
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1900
.addReg(AArch64::X17)
1901
.addReg(AArch64::XZR)
1902
.addReg(AArch64::X16)
1903
.addImm(0));
1904
++InstsEmitted;
1905
1906
// xpaci x17
1907
EmitToStreamer(
1908
*OutStreamer,
1909
MCInstBuilder(XPACOpc).addReg(AArch64::X17).addReg(AArch64::X17));
1910
++InstsEmitted;
1911
1912
// cmp x16, x17
1913
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs)
1914
.addReg(AArch64::XZR)
1915
.addReg(AArch64::X16)
1916
.addReg(AArch64::X17)
1917
.addImm(0));
1918
++InstsEmitted;
1919
1920
// b.eq Lsuccess
1921
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::Bcc)
1922
.addImm(AArch64CC::EQ)
1923
.addExpr(MCSymbolRefExpr::create(
1924
SuccessSym, OutContext)));
1925
++InstsEmitted;
1926
1927
if (ShouldTrap) {
1928
// Trapping sequences do a 'brk'.
1929
// brk #<0xc470 + aut key>
1930
EmitToStreamer(*OutStreamer,
1931
MCInstBuilder(AArch64::BRK).addImm(0xc470 | AUTKey));
1932
++InstsEmitted;
1933
} else {
1934
// Non-trapping checked sequences return the stripped result in x16,
1935
// skipping over the PAC if there is one.
1936
1937
// FIXME: can we simply return the AUT result, already in x16? without..
1938
// ..traps this is usable as an oracle anyway, based on high bits
1939
// mov x17, x16
1940
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1941
.addReg(AArch64::X16)
1942
.addReg(AArch64::XZR)
1943
.addReg(AArch64::X17)
1944
.addImm(0));
1945
++InstsEmitted;
1946
1947
if (IsAUTPAC) {
1948
EndSym = createTempSymbol("resign_end_");
1949
1950
// b Lend
1951
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B)
1952
.addExpr(MCSymbolRefExpr::create(
1953
EndSym, OutContext)));
1954
++InstsEmitted;
1955
}
1956
}
1957
1958
// If the auth check succeeds, we can continue.
1959
// Lsuccess:
1960
OutStreamer->emitLabel(SuccessSym);
1961
}
1962
1963
// We already emitted unchecked and checked-but-non-trapping AUTs.
1964
// That left us with trapping AUTs, and AUTPACs.
1965
// Trapping AUTs don't need PAC: we're done.
1966
if (!IsAUTPAC) {
1967
assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
1968
return;
1969
}
1970
1971
auto PACKey = (AArch64PACKey::ID)MI->getOperand(3).getImm();
1972
uint64_t PACDisc = MI->getOperand(4).getImm();
1973
unsigned PACAddrDisc = MI->getOperand(5).getReg();
1974
1975
// Compute pac discriminator into x17
1976
assert(isUInt<16>(PACDisc));
1977
unsigned PACDiscReg =
1978
emitPtrauthDiscriminator(PACDisc, PACAddrDisc, InstsEmitted);
1979
bool PACZero = PACDiscReg == AArch64::XZR;
1980
unsigned PACOpc = getPACOpcodeForKey(PACKey, PACZero);
1981
1982
// pacizb x16 ; if PACZero
1983
// pacib x16, x17 ; if !PACZero
1984
MCInst PACInst;
1985
PACInst.setOpcode(PACOpc);
1986
PACInst.addOperand(MCOperand::createReg(AArch64::X16));
1987
PACInst.addOperand(MCOperand::createReg(AArch64::X16));
1988
if (!PACZero)
1989
PACInst.addOperand(MCOperand::createReg(PACDiscReg));
1990
EmitToStreamer(*OutStreamer, PACInst);
1991
++InstsEmitted;
1992
1993
assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
1994
// Lend:
1995
if (EndSym)
1996
OutStreamer->emitLabel(EndSym);
1997
}
1998
1999
void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
2000
unsigned InstsEmitted = 0;
2001
bool IsCall = MI->getOpcode() == AArch64::BLRA;
2002
unsigned BrTarget = MI->getOperand(0).getReg();
2003
2004
auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm();
2005
assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
2006
"Invalid auth call key");
2007
2008
uint64_t Disc = MI->getOperand(2).getImm();
2009
assert(isUInt<16>(Disc));
2010
2011
unsigned AddrDisc = MI->getOperand(3).getReg();
2012
2013
// Compute discriminator into x17
2014
unsigned DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, InstsEmitted);
2015
bool IsZeroDisc = DiscReg == AArch64::XZR;
2016
2017
unsigned Opc;
2018
if (IsCall) {
2019
if (Key == AArch64PACKey::IA)
2020
Opc = IsZeroDisc ? AArch64::BLRAAZ : AArch64::BLRAA;
2021
else
2022
Opc = IsZeroDisc ? AArch64::BLRABZ : AArch64::BLRAB;
2023
} else {
2024
if (Key == AArch64PACKey::IA)
2025
Opc = IsZeroDisc ? AArch64::BRAAZ : AArch64::BRAA;
2026
else
2027
Opc = IsZeroDisc ? AArch64::BRABZ : AArch64::BRAB;
2028
}
2029
2030
MCInst BRInst;
2031
BRInst.setOpcode(Opc);
2032
BRInst.addOperand(MCOperand::createReg(BrTarget));
2033
if (!IsZeroDisc)
2034
BRInst.addOperand(MCOperand::createReg(DiscReg));
2035
EmitToStreamer(*OutStreamer, BRInst);
2036
++InstsEmitted;
2037
2038
assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
2039
}
2040
2041
const MCExpr *
2042
AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2043
MCContext &Ctx = OutContext;
2044
2045
// Figure out the base symbol and the addend, if any.
2046
APInt Offset(64, 0);
2047
const Value *BaseGV = CPA.getPointer()->stripAndAccumulateConstantOffsets(
2048
getDataLayout(), Offset, /*AllowNonInbounds=*/true);
2049
2050
auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
2051
2052
// If we can't understand the referenced ConstantExpr, there's nothing
2053
// else we can do: emit an error.
2054
if (!BaseGVB) {
2055
BaseGV->getContext().emitError(
2056
"cannot resolve target base/addend of ptrauth constant");
2057
return nullptr;
2058
}
2059
2060
// If there is an addend, turn that into the appropriate MCExpr.
2061
const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2062
if (Offset.sgt(0))
2063
Sym = MCBinaryExpr::createAdd(
2064
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2065
else if (Offset.slt(0))
2066
Sym = MCBinaryExpr::createSub(
2067
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2068
2069
uint64_t KeyID = CPA.getKey()->getZExtValue();
2070
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
2071
// AArch64AuthMCExpr::printImpl, so fail fast.
2072
if (KeyID > AArch64PACKey::LAST)
2073
report_fatal_error("AArch64 PAC Key ID '" + Twine(KeyID) +
2074
"' out of range [0, " +
2075
Twine((unsigned)AArch64PACKey::LAST) + "]");
2076
2077
uint64_t Disc = CPA.getDiscriminator()->getZExtValue();
2078
if (!isUInt<16>(Disc))
2079
report_fatal_error("AArch64 PAC Discriminator '" + Twine(Disc) +
2080
"' out of range [0, 0xFFFF]");
2081
2082
// Finally build the complete @AUTH expr.
2083
return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
2084
CPA.hasAddressDiscriminator(), Ctx);
2085
}
2086
2087
void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
2088
unsigned DstReg = MI.getOperand(0).getReg();
2089
const MachineOperand &GAOp = MI.getOperand(1);
2090
const uint64_t KeyC = MI.getOperand(2).getImm();
2091
assert(KeyC <= AArch64PACKey::LAST &&
2092
"key is out of range [0, AArch64PACKey::LAST]");
2093
const auto Key = (AArch64PACKey::ID)KeyC;
2094
const uint64_t Disc = MI.getOperand(3).getImm();
2095
assert(isUInt<16>(Disc) &&
2096
"constant discriminator is out of range [0, 0xffff]");
2097
2098
// Emit instruction sequence like the following:
2099
// ADRP x16, symbol$auth_ptr$key$disc
2100
// LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc]
2101
//
2102
// Where the $auth_ptr$ symbol is the stub slot containing the signed pointer
2103
// to symbol.
2104
MCSymbol *AuthPtrStubSym;
2105
if (TM.getTargetTriple().isOSBinFormatELF()) {
2106
const auto &TLOF =
2107
static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering());
2108
2109
assert(GAOp.getOffset() == 0 &&
2110
"non-zero offset for $auth_ptr$ stub slots is not supported");
2111
const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
2112
AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
2113
} else {
2114
assert(TM.getTargetTriple().isOSBinFormatMachO() &&
2115
"LOADauthptrstatic is implemented only for MachO/ELF");
2116
2117
const auto &TLOF = static_cast<const AArch64_MachoTargetObjectFile &>(
2118
getObjFileLowering());
2119
2120
assert(GAOp.getOffset() == 0 &&
2121
"non-zero offset for $auth_ptr$ stub slots is not supported");
2122
const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
2123
AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
2124
}
2125
2126
MachineOperand StubMOHi =
2127
MachineOperand::CreateMCSymbol(AuthPtrStubSym, AArch64II::MO_PAGE);
2128
MachineOperand StubMOLo = MachineOperand::CreateMCSymbol(
2129
AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2130
MCOperand StubMCHi, StubMCLo;
2131
2132
MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
2133
MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
2134
2135
EmitToStreamer(
2136
*OutStreamer,
2137
MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi));
2138
2139
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui)
2140
.addReg(DstReg)
2141
.addReg(DstReg)
2142
.addOperand(StubMCLo));
2143
}
2144
2145
void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2146
unsigned InstsEmitted = 0;
2147
auto EmitAndIncrement = [this, &InstsEmitted](const MCInst &Inst) {
2148
EmitToStreamer(*OutStreamer, Inst);
2149
++InstsEmitted;
2150
};
2151
2152
const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC;
2153
MachineOperand GAOp = MI.getOperand(0);
2154
const uint64_t KeyC = MI.getOperand(1).getImm();
2155
assert(KeyC <= AArch64PACKey::LAST &&
2156
"key is out of range [0, AArch64PACKey::LAST]");
2157
const auto Key = (AArch64PACKey::ID)KeyC;
2158
const unsigned AddrDisc = MI.getOperand(2).getReg();
2159
const uint64_t Disc = MI.getOperand(3).getImm();
2160
assert(isUInt<16>(Disc) &&
2161
"constant discriminator is out of range [0, 0xffff]");
2162
2163
const int64_t Offset = GAOp.getOffset();
2164
GAOp.setOffset(0);
2165
2166
// Emit:
2167
// target materialization:
2168
// - via GOT:
2169
// adrp x16, :got:target
2170
// ldr x16, [x16, :got_lo12:target]
2171
// add offset to x16 if offset != 0
2172
//
2173
// - direct:
2174
// adrp x16, target
2175
// add x16, x16, :lo12:target
2176
// add offset to x16 if offset != 0
2177
//
2178
// add offset to x16:
2179
// - abs(offset) fits 24 bits:
2180
// add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions)
2181
// - abs(offset) does not fit 24 bits:
2182
// - offset < 0:
2183
// movn+movk sequence filling x17 register with the offset (up to 4
2184
// instructions)
2185
// add x16, x16, x17
2186
// - offset > 0:
2187
// movz+movk sequence filling x17 register with the offset (up to 4
2188
// instructions)
2189
// add x16, x16, x17
2190
//
2191
// signing:
2192
// - 0 discriminator:
2193
// paciza x16
2194
// - Non-0 discriminator, no address discriminator:
2195
// mov x17, #Disc
2196
// pacia x16, x17
2197
// - address discriminator (with potentially folded immediate discriminator):
2198
// pacia x16, xAddrDisc
2199
2200
MachineOperand GAMOHi(GAOp), GAMOLo(GAOp);
2201
MCOperand GAMCHi, GAMCLo;
2202
2203
GAMOHi.setTargetFlags(AArch64II::MO_PAGE);
2204
GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2205
if (IsGOTLoad) {
2206
GAMOHi.addTargetFlag(AArch64II::MO_GOT);
2207
GAMOLo.addTargetFlag(AArch64II::MO_GOT);
2208
}
2209
2210
MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
2211
MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
2212
2213
EmitAndIncrement(
2214
MCInstBuilder(AArch64::ADRP).addReg(AArch64::X16).addOperand(GAMCHi));
2215
2216
if (IsGOTLoad) {
2217
EmitAndIncrement(MCInstBuilder(AArch64::LDRXui)
2218
.addReg(AArch64::X16)
2219
.addReg(AArch64::X16)
2220
.addOperand(GAMCLo));
2221
} else {
2222
EmitAndIncrement(MCInstBuilder(AArch64::ADDXri)
2223
.addReg(AArch64::X16)
2224
.addReg(AArch64::X16)
2225
.addOperand(GAMCLo)
2226
.addImm(0));
2227
}
2228
2229
if (Offset != 0) {
2230
const uint64_t AbsOffset = (Offset > 0 ? Offset : -((uint64_t)Offset));
2231
const bool IsNeg = Offset < 0;
2232
if (isUInt<24>(AbsOffset)) {
2233
for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
2234
BitPos += 12) {
2235
EmitAndIncrement(
2236
MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri)
2237
.addReg(AArch64::X16)
2238
.addReg(AArch64::X16)
2239
.addImm((AbsOffset >> BitPos) & 0xfff)
2240
.addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
2241
}
2242
} else {
2243
const uint64_t UOffset = Offset;
2244
EmitAndIncrement(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
2245
.addReg(AArch64::X17)
2246
.addImm((IsNeg ? ~UOffset : UOffset) & 0xffff)
2247
.addImm(/*shift=*/0));
2248
auto NeedMovk = [IsNeg, UOffset](int BitPos) -> bool {
2249
assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
2250
uint64_t Shifted = UOffset >> BitPos;
2251
if (!IsNeg)
2252
return Shifted != 0;
2253
for (int I = 0; I != 64 - BitPos; I += 16)
2254
if (((Shifted >> I) & 0xffff) != 0xffff)
2255
return true;
2256
return false;
2257
};
2258
for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) {
2259
EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
2260
.addReg(AArch64::X17)
2261
.addReg(AArch64::X17)
2262
.addImm((UOffset >> BitPos) & 0xffff)
2263
.addImm(/*shift=*/BitPos));
2264
}
2265
EmitAndIncrement(MCInstBuilder(AArch64::ADDXrs)
2266
.addReg(AArch64::X16)
2267
.addReg(AArch64::X16)
2268
.addReg(AArch64::X17)
2269
.addImm(/*shift=*/0));
2270
}
2271
}
2272
2273
unsigned DiscReg = AddrDisc;
2274
if (Disc != 0) {
2275
if (AddrDisc != AArch64::XZR) {
2276
EmitAndIncrement(MCInstBuilder(AArch64::ORRXrs)
2277
.addReg(AArch64::X17)
2278
.addReg(AArch64::XZR)
2279
.addReg(AddrDisc)
2280
.addImm(0));
2281
EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
2282
.addReg(AArch64::X17)
2283
.addReg(AArch64::X17)
2284
.addImm(Disc)
2285
.addImm(/*shift=*/48));
2286
} else {
2287
EmitAndIncrement(MCInstBuilder(AArch64::MOVZXi)
2288
.addReg(AArch64::X17)
2289
.addImm(Disc)
2290
.addImm(/*shift=*/0));
2291
}
2292
DiscReg = AArch64::X17;
2293
}
2294
2295
auto MIB = MCInstBuilder(getPACOpcodeForKey(Key, DiscReg == AArch64::XZR))
2296
.addReg(AArch64::X16)
2297
.addReg(AArch64::X16);
2298
if (DiscReg != AArch64::XZR)
2299
MIB.addReg(DiscReg);
2300
EmitAndIncrement(MIB);
2301
2302
assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4);
2303
}
2304
2305
const MCExpr *
2306
AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) {
2307
const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant(BA);
2308
const Function &Fn = *BA.getFunction();
2309
2310
if (std::optional<uint16_t> BADisc =
2311
STI->getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn))
2312
return AArch64AuthMCExpr::create(BAE, *BADisc, AArch64PACKey::IA,
2313
/*HasAddressDiversity=*/false, OutContext);
2314
2315
return BAE;
2316
}
2317
2318
// Simple pseudo-instructions have their lowering (with expansion to real
2319
// instructions) auto-generated.
2320
#include "AArch64GenMCPseudoLowering.inc"
2321
2322
void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
2323
AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
2324
2325
// Do any auto-generated pseudo lowerings.
2326
if (emitPseudoExpansionLowering(*OutStreamer, MI))
2327
return;
2328
2329
if (MI->getOpcode() == AArch64::ADRP) {
2330
for (auto &Opd : MI->operands()) {
2331
if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) ==
2332
"swift_async_extendedFramePointerFlags") {
2333
ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true;
2334
}
2335
}
2336
}
2337
2338
if (AArch64FI->getLOHRelated().count(MI)) {
2339
// Generate a label for LOH related instruction
2340
MCSymbol *LOHLabel = createTempSymbol("loh");
2341
// Associate the instruction with the label
2342
LOHInstToLabel[MI] = LOHLabel;
2343
OutStreamer->emitLabel(LOHLabel);
2344
}
2345
2346
AArch64TargetStreamer *TS =
2347
static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
2348
// Do any manual lowerings.
2349
switch (MI->getOpcode()) {
2350
default:
2351
break;
2352
case AArch64::HINT: {
2353
// CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for
2354
// -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be
2355
// non-empty. If MI is the initial BTI, place the
2356
// __patchable_function_entries label after BTI.
2357
if (CurrentPatchableFunctionEntrySym &&
2358
CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
2359
MI == &MF->front().front()) {
2360
int64_t Imm = MI->getOperand(0).getImm();
2361
if ((Imm & 32) && (Imm & 6)) {
2362
MCInst Inst;
2363
MCInstLowering.Lower(MI, Inst);
2364
EmitToStreamer(*OutStreamer, Inst);
2365
CurrentPatchableFunctionEntrySym = createTempSymbol("patch");
2366
OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym);
2367
return;
2368
}
2369
}
2370
break;
2371
}
2372
case AArch64::MOVMCSym: {
2373
Register DestReg = MI->getOperand(0).getReg();
2374
const MachineOperand &MO_Sym = MI->getOperand(1);
2375
MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
2376
MCOperand Hi_MCSym, Lo_MCSym;
2377
2378
Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
2379
Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
2380
2381
MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
2382
MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
2383
2384
MCInst MovZ;
2385
MovZ.setOpcode(AArch64::MOVZXi);
2386
MovZ.addOperand(MCOperand::createReg(DestReg));
2387
MovZ.addOperand(Hi_MCSym);
2388
MovZ.addOperand(MCOperand::createImm(16));
2389
EmitToStreamer(*OutStreamer, MovZ);
2390
2391
MCInst MovK;
2392
MovK.setOpcode(AArch64::MOVKXi);
2393
MovK.addOperand(MCOperand::createReg(DestReg));
2394
MovK.addOperand(MCOperand::createReg(DestReg));
2395
MovK.addOperand(Lo_MCSym);
2396
MovK.addOperand(MCOperand::createImm(0));
2397
EmitToStreamer(*OutStreamer, MovK);
2398
return;
2399
}
2400
case AArch64::MOVIv2d_ns:
2401
// It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0".
2402
// as movi is more efficient across all cores. Newer cores can eliminate
2403
// fmovs early and there is no difference with movi, but this not true for
2404
// all implementations.
2405
//
2406
// The floating-point version doesn't quite work in rare cases on older
2407
// CPUs, so on those targets we lower this instruction to movi.16b instead.
2408
if (STI->hasZeroCycleZeroingFPWorkaround() &&
2409
MI->getOperand(1).getImm() == 0) {
2410
MCInst TmpInst;
2411
TmpInst.setOpcode(AArch64::MOVIv16b_ns);
2412
TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
2413
TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
2414
EmitToStreamer(*OutStreamer, TmpInst);
2415
return;
2416
}
2417
break;
2418
2419
case AArch64::DBG_VALUE:
2420
case AArch64::DBG_VALUE_LIST:
2421
if (isVerbose() && OutStreamer->hasRawTextSupport()) {
2422
SmallString<128> TmpStr;
2423
raw_svector_ostream OS(TmpStr);
2424
PrintDebugValueComment(MI, OS);
2425
OutStreamer->emitRawText(StringRef(OS.str()));
2426
}
2427
return;
2428
2429
case AArch64::EMITBKEY: {
2430
ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
2431
if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
2432
ExceptionHandlingType != ExceptionHandling::ARM)
2433
return;
2434
2435
if (getFunctionCFISectionType(*MF) == CFISection::None)
2436
return;
2437
2438
OutStreamer->emitCFIBKeyFrame();
2439
return;
2440
}
2441
2442
case AArch64::EMITMTETAGGED: {
2443
ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
2444
if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
2445
ExceptionHandlingType != ExceptionHandling::ARM)
2446
return;
2447
2448
if (getFunctionCFISectionType(*MF) != CFISection::None)
2449
OutStreamer->emitCFIMTETaggedFrame();
2450
return;
2451
}
2452
2453
case AArch64::AUT:
2454
case AArch64::AUTPAC:
2455
emitPtrauthAuthResign(MI);
2456
return;
2457
2458
case AArch64::LOADauthptrstatic:
2459
LowerLOADauthptrstatic(*MI);
2460
return;
2461
2462
case AArch64::LOADgotPAC:
2463
case AArch64::MOVaddrPAC:
2464
LowerMOVaddrPAC(*MI);
2465
return;
2466
2467
case AArch64::BRA:
2468
case AArch64::BLRA:
2469
emitPtrauthBranch(MI);
2470
return;
2471
2472
// Tail calls use pseudo instructions so they have the proper code-gen
2473
// attributes (isCall, isReturn, etc.). We lower them to the real
2474
// instruction here.
2475
case AArch64::AUTH_TCRETURN:
2476
case AArch64::AUTH_TCRETURN_BTI: {
2477
const uint64_t Key = MI->getOperand(2).getImm();
2478
assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
2479
"Invalid auth key for tail-call return");
2480
2481
const uint64_t Disc = MI->getOperand(3).getImm();
2482
assert(isUInt<16>(Disc) && "Integer discriminator is too wide");
2483
2484
Register AddrDisc = MI->getOperand(4).getReg();
2485
2486
Register ScratchReg = MI->getOperand(0).getReg() == AArch64::X16
2487
? AArch64::X17
2488
: AArch64::X16;
2489
2490
unsigned DiscReg = AddrDisc;
2491
if (Disc) {
2492
if (AddrDisc != AArch64::NoRegister) {
2493
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
2494
.addReg(ScratchReg)
2495
.addReg(AArch64::XZR)
2496
.addReg(AddrDisc)
2497
.addImm(0));
2498
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
2499
.addReg(ScratchReg)
2500
.addReg(ScratchReg)
2501
.addImm(Disc)
2502
.addImm(/*shift=*/48));
2503
} else {
2504
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
2505
.addReg(ScratchReg)
2506
.addImm(Disc)
2507
.addImm(/*shift=*/0));
2508
}
2509
DiscReg = ScratchReg;
2510
}
2511
2512
const bool IsZero = DiscReg == AArch64::NoRegister;
2513
const unsigned Opcodes[2][2] = {{AArch64::BRAA, AArch64::BRAAZ},
2514
{AArch64::BRAB, AArch64::BRABZ}};
2515
2516
MCInst TmpInst;
2517
TmpInst.setOpcode(Opcodes[Key][IsZero]);
2518
TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
2519
if (!IsZero)
2520
TmpInst.addOperand(MCOperand::createReg(DiscReg));
2521
EmitToStreamer(*OutStreamer, TmpInst);
2522
return;
2523
}
2524
2525
case AArch64::TCRETURNri:
2526
case AArch64::TCRETURNrix16x17:
2527
case AArch64::TCRETURNrix17:
2528
case AArch64::TCRETURNrinotx16:
2529
case AArch64::TCRETURNriALL: {
2530
MCInst TmpInst;
2531
TmpInst.setOpcode(AArch64::BR);
2532
TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
2533
EmitToStreamer(*OutStreamer, TmpInst);
2534
return;
2535
}
2536
case AArch64::TCRETURNdi: {
2537
MCOperand Dest;
2538
MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
2539
MCInst TmpInst;
2540
TmpInst.setOpcode(AArch64::B);
2541
TmpInst.addOperand(Dest);
2542
EmitToStreamer(*OutStreamer, TmpInst);
2543
return;
2544
}
2545
case AArch64::SpeculationBarrierISBDSBEndBB: {
2546
// Print DSB SYS + ISB
2547
MCInst TmpInstDSB;
2548
TmpInstDSB.setOpcode(AArch64::DSB);
2549
TmpInstDSB.addOperand(MCOperand::createImm(0xf));
2550
EmitToStreamer(*OutStreamer, TmpInstDSB);
2551
MCInst TmpInstISB;
2552
TmpInstISB.setOpcode(AArch64::ISB);
2553
TmpInstISB.addOperand(MCOperand::createImm(0xf));
2554
EmitToStreamer(*OutStreamer, TmpInstISB);
2555
return;
2556
}
2557
case AArch64::SpeculationBarrierSBEndBB: {
2558
// Print SB
2559
MCInst TmpInstSB;
2560
TmpInstSB.setOpcode(AArch64::SB);
2561
EmitToStreamer(*OutStreamer, TmpInstSB);
2562
return;
2563
}
2564
case AArch64::TLSDESC_CALLSEQ: {
2565
/// lower this to:
2566
/// adrp x0, :tlsdesc:var
2567
/// ldr x1, [x0, #:tlsdesc_lo12:var]
2568
/// add x0, x0, #:tlsdesc_lo12:var
2569
/// .tlsdesccall var
2570
/// blr x1
2571
/// (TPIDR_EL0 offset now in x0)
2572
const MachineOperand &MO_Sym = MI->getOperand(0);
2573
MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
2574
MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
2575
MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
2576
MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
2577
MCInstLowering.lowerOperand(MO_Sym, Sym);
2578
MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
2579
MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
2580
2581
MCInst Adrp;
2582
Adrp.setOpcode(AArch64::ADRP);
2583
Adrp.addOperand(MCOperand::createReg(AArch64::X0));
2584
Adrp.addOperand(SymTLSDesc);
2585
EmitToStreamer(*OutStreamer, Adrp);
2586
2587
MCInst Ldr;
2588
if (STI->isTargetILP32()) {
2589
Ldr.setOpcode(AArch64::LDRWui);
2590
Ldr.addOperand(MCOperand::createReg(AArch64::W1));
2591
} else {
2592
Ldr.setOpcode(AArch64::LDRXui);
2593
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
2594
}
2595
Ldr.addOperand(MCOperand::createReg(AArch64::X0));
2596
Ldr.addOperand(SymTLSDescLo12);
2597
Ldr.addOperand(MCOperand::createImm(0));
2598
EmitToStreamer(*OutStreamer, Ldr);
2599
2600
MCInst Add;
2601
if (STI->isTargetILP32()) {
2602
Add.setOpcode(AArch64::ADDWri);
2603
Add.addOperand(MCOperand::createReg(AArch64::W0));
2604
Add.addOperand(MCOperand::createReg(AArch64::W0));
2605
} else {
2606
Add.setOpcode(AArch64::ADDXri);
2607
Add.addOperand(MCOperand::createReg(AArch64::X0));
2608
Add.addOperand(MCOperand::createReg(AArch64::X0));
2609
}
2610
Add.addOperand(SymTLSDescLo12);
2611
Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
2612
EmitToStreamer(*OutStreamer, Add);
2613
2614
// Emit a relocation-annotation. This expands to no code, but requests
2615
// the following instruction gets an R_AARCH64_TLSDESC_CALL.
2616
MCInst TLSDescCall;
2617
TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
2618
TLSDescCall.addOperand(Sym);
2619
EmitToStreamer(*OutStreamer, TLSDescCall);
2620
2621
MCInst Blr;
2622
Blr.setOpcode(AArch64::BLR);
2623
Blr.addOperand(MCOperand::createReg(AArch64::X1));
2624
EmitToStreamer(*OutStreamer, Blr);
2625
2626
return;
2627
}
2628
2629
case AArch64::JumpTableDest32:
2630
case AArch64::JumpTableDest16:
2631
case AArch64::JumpTableDest8:
2632
LowerJumpTableDest(*OutStreamer, *MI);
2633
return;
2634
2635
case AArch64::BR_JumpTable:
2636
LowerHardenedBRJumpTable(*MI);
2637
return;
2638
2639
case AArch64::FMOVH0:
2640
case AArch64::FMOVS0:
2641
case AArch64::FMOVD0:
2642
emitFMov0(*MI);
2643
return;
2644
2645
case AArch64::MOPSMemoryCopyPseudo:
2646
case AArch64::MOPSMemoryMovePseudo:
2647
case AArch64::MOPSMemorySetPseudo:
2648
case AArch64::MOPSMemorySetTaggingPseudo:
2649
LowerMOPS(*OutStreamer, *MI);
2650
return;
2651
2652
case TargetOpcode::STACKMAP:
2653
return LowerSTACKMAP(*OutStreamer, SM, *MI);
2654
2655
case TargetOpcode::PATCHPOINT:
2656
return LowerPATCHPOINT(*OutStreamer, SM, *MI);
2657
2658
case TargetOpcode::STATEPOINT:
2659
return LowerSTATEPOINT(*OutStreamer, SM, *MI);
2660
2661
case TargetOpcode::FAULTING_OP:
2662
return LowerFAULTING_OP(*MI);
2663
2664
case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
2665
LowerPATCHABLE_FUNCTION_ENTER(*MI);
2666
return;
2667
2668
case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
2669
LowerPATCHABLE_FUNCTION_EXIT(*MI);
2670
return;
2671
2672
case TargetOpcode::PATCHABLE_TAIL_CALL:
2673
LowerPATCHABLE_TAIL_CALL(*MI);
2674
return;
2675
case TargetOpcode::PATCHABLE_EVENT_CALL:
2676
return LowerPATCHABLE_EVENT_CALL(*MI, false);
2677
case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
2678
return LowerPATCHABLE_EVENT_CALL(*MI, true);
2679
2680
case AArch64::KCFI_CHECK:
2681
LowerKCFI_CHECK(*MI);
2682
return;
2683
2684
case AArch64::HWASAN_CHECK_MEMACCESS:
2685
case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
2686
case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
2687
case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
2688
LowerHWASAN_CHECK_MEMACCESS(*MI);
2689
return;
2690
2691
case AArch64::SEH_StackAlloc:
2692
TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
2693
return;
2694
2695
case AArch64::SEH_SaveFPLR:
2696
TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
2697
return;
2698
2699
case AArch64::SEH_SaveFPLR_X:
2700
assert(MI->getOperand(0).getImm() < 0 &&
2701
"Pre increment SEH opcode must have a negative offset");
2702
TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
2703
return;
2704
2705
case AArch64::SEH_SaveReg:
2706
TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
2707
MI->getOperand(1).getImm());
2708
return;
2709
2710
case AArch64::SEH_SaveReg_X:
2711
assert(MI->getOperand(1).getImm() < 0 &&
2712
"Pre increment SEH opcode must have a negative offset");
2713
TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
2714
-MI->getOperand(1).getImm());
2715
return;
2716
2717
case AArch64::SEH_SaveRegP:
2718
if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 &&
2719
MI->getOperand(0).getImm() <= 28) {
2720
assert((MI->getOperand(0).getImm() - 19) % 2 == 0 &&
2721
"Register paired with LR must be odd");
2722
TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(),
2723
MI->getOperand(2).getImm());
2724
return;
2725
}
2726
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2727
"Non-consecutive registers not allowed for save_regp");
2728
TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
2729
MI->getOperand(2).getImm());
2730
return;
2731
2732
case AArch64::SEH_SaveRegP_X:
2733
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2734
"Non-consecutive registers not allowed for save_regp_x");
2735
assert(MI->getOperand(2).getImm() < 0 &&
2736
"Pre increment SEH opcode must have a negative offset");
2737
TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
2738
-MI->getOperand(2).getImm());
2739
return;
2740
2741
case AArch64::SEH_SaveFReg:
2742
TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
2743
MI->getOperand(1).getImm());
2744
return;
2745
2746
case AArch64::SEH_SaveFReg_X:
2747
assert(MI->getOperand(1).getImm() < 0 &&
2748
"Pre increment SEH opcode must have a negative offset");
2749
TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
2750
-MI->getOperand(1).getImm());
2751
return;
2752
2753
case AArch64::SEH_SaveFRegP:
2754
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2755
"Non-consecutive registers not allowed for save_regp");
2756
TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
2757
MI->getOperand(2).getImm());
2758
return;
2759
2760
case AArch64::SEH_SaveFRegP_X:
2761
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2762
"Non-consecutive registers not allowed for save_regp_x");
2763
assert(MI->getOperand(2).getImm() < 0 &&
2764
"Pre increment SEH opcode must have a negative offset");
2765
TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
2766
-MI->getOperand(2).getImm());
2767
return;
2768
2769
case AArch64::SEH_SetFP:
2770
TS->emitARM64WinCFISetFP();
2771
return;
2772
2773
case AArch64::SEH_AddFP:
2774
TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm());
2775
return;
2776
2777
case AArch64::SEH_Nop:
2778
TS->emitARM64WinCFINop();
2779
return;
2780
2781
case AArch64::SEH_PrologEnd:
2782
TS->emitARM64WinCFIPrologEnd();
2783
return;
2784
2785
case AArch64::SEH_EpilogStart:
2786
TS->emitARM64WinCFIEpilogStart();
2787
return;
2788
2789
case AArch64::SEH_EpilogEnd:
2790
TS->emitARM64WinCFIEpilogEnd();
2791
return;
2792
2793
case AArch64::SEH_PACSignLR:
2794
TS->emitARM64WinCFIPACSignLR();
2795
return;
2796
2797
case AArch64::SEH_SaveAnyRegQP:
2798
assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
2799
"Non-consecutive registers not allowed for save_any_reg");
2800
assert(MI->getOperand(2).getImm() >= 0 &&
2801
"SaveAnyRegQP SEH opcode offset must be non-negative");
2802
assert(MI->getOperand(2).getImm() <= 1008 &&
2803
"SaveAnyRegQP SEH opcode offset must fit into 6 bits");
2804
TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(),
2805
MI->getOperand(2).getImm());
2806
return;
2807
2808
case AArch64::SEH_SaveAnyRegQPX:
2809
assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
2810
"Non-consecutive registers not allowed for save_any_reg");
2811
assert(MI->getOperand(2).getImm() < 0 &&
2812
"SaveAnyRegQPX SEH opcode offset must be negative");
2813
assert(MI->getOperand(2).getImm() >= -1008 &&
2814
"SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
2815
TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(),
2816
-MI->getOperand(2).getImm());
2817
return;
2818
}
2819
2820
// Finally, do the automated lowerings for everything else.
2821
MCInst TmpInst;
2822
MCInstLowering.Lower(MI, TmpInst);
2823
EmitToStreamer(*OutStreamer, TmpInst);
2824
}
2825
2826
void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
2827
MCSymbol *LazyPointer) {
2828
// _ifunc:
2829
// adrp x16, lazy_pointer@GOTPAGE
2830
// ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
2831
// ldr x16, [x16]
2832
// br x16
2833
2834
{
2835
MCInst Adrp;
2836
Adrp.setOpcode(AArch64::ADRP);
2837
Adrp.addOperand(MCOperand::createReg(AArch64::X16));
2838
MCOperand SymPage;
2839
MCInstLowering.lowerOperand(
2840
MachineOperand::CreateMCSymbol(LazyPointer,
2841
AArch64II::MO_GOT | AArch64II::MO_PAGE),
2842
SymPage);
2843
Adrp.addOperand(SymPage);
2844
OutStreamer->emitInstruction(Adrp, *STI);
2845
}
2846
2847
{
2848
MCInst Ldr;
2849
Ldr.setOpcode(AArch64::LDRXui);
2850
Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2851
Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2852
MCOperand SymPageOff;
2853
MCInstLowering.lowerOperand(
2854
MachineOperand::CreateMCSymbol(LazyPointer, AArch64II::MO_GOT |
2855
AArch64II::MO_PAGEOFF),
2856
SymPageOff);
2857
Ldr.addOperand(SymPageOff);
2858
Ldr.addOperand(MCOperand::createImm(0));
2859
OutStreamer->emitInstruction(Ldr, *STI);
2860
}
2861
2862
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
2863
.addReg(AArch64::X16)
2864
.addReg(AArch64::X16)
2865
.addImm(0),
2866
*STI);
2867
2868
OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
2869
? AArch64::BRAAZ
2870
: AArch64::BR)
2871
.addReg(AArch64::X16),
2872
*STI);
2873
}
2874
2875
void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
2876
const GlobalIFunc &GI,
2877
MCSymbol *LazyPointer) {
2878
// These stub helpers are only ever called once, so here we're optimizing for
2879
// minimum size by using the pre-indexed store variants, which saves a few
2880
// bytes of instructions to bump & restore sp.
2881
2882
// _ifunc.stub_helper:
2883
// stp fp, lr, [sp, #-16]!
2884
// mov fp, sp
2885
// stp x1, x0, [sp, #-16]!
2886
// stp x3, x2, [sp, #-16]!
2887
// stp x5, x4, [sp, #-16]!
2888
// stp x7, x6, [sp, #-16]!
2889
// stp d1, d0, [sp, #-16]!
2890
// stp d3, d2, [sp, #-16]!
2891
// stp d5, d4, [sp, #-16]!
2892
// stp d7, d6, [sp, #-16]!
2893
// bl _resolver
2894
// adrp x16, lazy_pointer@GOTPAGE
2895
// ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
2896
// str x0, [x16]
2897
// mov x16, x0
2898
// ldp d7, d6, [sp], #16
2899
// ldp d5, d4, [sp], #16
2900
// ldp d3, d2, [sp], #16
2901
// ldp d1, d0, [sp], #16
2902
// ldp x7, x6, [sp], #16
2903
// ldp x5, x4, [sp], #16
2904
// ldp x3, x2, [sp], #16
2905
// ldp x1, x0, [sp], #16
2906
// ldp fp, lr, [sp], #16
2907
// br x16
2908
2909
OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
2910
.addReg(AArch64::SP)
2911
.addReg(AArch64::FP)
2912
.addReg(AArch64::LR)
2913
.addReg(AArch64::SP)
2914
.addImm(-2),
2915
*STI);
2916
2917
OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
2918
.addReg(AArch64::FP)
2919
.addReg(AArch64::SP)
2920
.addImm(0)
2921
.addImm(0),
2922
*STI);
2923
2924
for (int I = 0; I != 4; ++I)
2925
OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
2926
.addReg(AArch64::SP)
2927
.addReg(AArch64::X1 + 2 * I)
2928
.addReg(AArch64::X0 + 2 * I)
2929
.addReg(AArch64::SP)
2930
.addImm(-2),
2931
*STI);
2932
2933
for (int I = 0; I != 4; ++I)
2934
OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
2935
.addReg(AArch64::SP)
2936
.addReg(AArch64::D1 + 2 * I)
2937
.addReg(AArch64::D0 + 2 * I)
2938
.addReg(AArch64::SP)
2939
.addImm(-2),
2940
*STI);
2941
2942
OutStreamer->emitInstruction(
2943
MCInstBuilder(AArch64::BL)
2944
.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
2945
*STI);
2946
2947
{
2948
MCInst Adrp;
2949
Adrp.setOpcode(AArch64::ADRP);
2950
Adrp.addOperand(MCOperand::createReg(AArch64::X16));
2951
MCOperand SymPage;
2952
MCInstLowering.lowerOperand(
2953
MachineOperand::CreateES(LazyPointer->getName().data() + 1,
2954
AArch64II::MO_GOT | AArch64II::MO_PAGE),
2955
SymPage);
2956
Adrp.addOperand(SymPage);
2957
OutStreamer->emitInstruction(Adrp, *STI);
2958
}
2959
2960
{
2961
MCInst Ldr;
2962
Ldr.setOpcode(AArch64::LDRXui);
2963
Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2964
Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2965
MCOperand SymPageOff;
2966
MCInstLowering.lowerOperand(
2967
MachineOperand::CreateES(LazyPointer->getName().data() + 1,
2968
AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
2969
SymPageOff);
2970
Ldr.addOperand(SymPageOff);
2971
Ldr.addOperand(MCOperand::createImm(0));
2972
OutStreamer->emitInstruction(Ldr, *STI);
2973
}
2974
2975
OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
2976
.addReg(AArch64::X0)
2977
.addReg(AArch64::X16)
2978
.addImm(0),
2979
*STI);
2980
2981
OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
2982
.addReg(AArch64::X16)
2983
.addReg(AArch64::X0)
2984
.addImm(0)
2985
.addImm(0),
2986
*STI);
2987
2988
for (int I = 3; I != -1; --I)
2989
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
2990
.addReg(AArch64::SP)
2991
.addReg(AArch64::D1 + 2 * I)
2992
.addReg(AArch64::D0 + 2 * I)
2993
.addReg(AArch64::SP)
2994
.addImm(2),
2995
*STI);
2996
2997
for (int I = 3; I != -1; --I)
2998
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
2999
.addReg(AArch64::SP)
3000
.addReg(AArch64::X1 + 2 * I)
3001
.addReg(AArch64::X0 + 2 * I)
3002
.addReg(AArch64::SP)
3003
.addImm(2),
3004
*STI);
3005
3006
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
3007
.addReg(AArch64::SP)
3008
.addReg(AArch64::FP)
3009
.addReg(AArch64::LR)
3010
.addReg(AArch64::SP)
3011
.addImm(2),
3012
*STI);
3013
3014
OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
3015
? AArch64::BRAAZ
3016
: AArch64::BR)
3017
.addReg(AArch64::X16),
3018
*STI);
3019
}
3020
3021
const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV) {
3022
if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
3023
return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0),
3024
OutContext);
3025
}
3026
3027
return AsmPrinter::lowerConstant(CV);
3028
}
3029
3030
// Force static initialization.
3031
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() {
3032
RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
3033
RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget());
3034
RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target());
3035
RegisterAsmPrinter<AArch64AsmPrinter> W(getTheARM64_32Target());
3036
RegisterAsmPrinter<AArch64AsmPrinter> V(getTheAArch64_32Target());
3037
}
3038
3039