LLVM 24.0.0git
AArch64AsmPrinter.cpp
Go to the documentation of this file.
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 "AArch64AsmPrinter.h"
15#include "AArch64.h"
16#include "AArch64MCInstLower.h"
18#include "AArch64RegisterInfo.h"
19#include "AArch64Subtarget.h"
28#include "llvm/ADT/ScopeExit.h"
31#include "llvm/ADT/Statistic.h"
32#include "llvm/ADT/StringRef.h"
33#include "llvm/ADT/Twine.h"
48#include "llvm/IR/Analysis.h"
49#include "llvm/IR/DataLayout.h"
51#include "llvm/IR/Mangler.h"
52#include "llvm/IR/Module.h"
53#include "llvm/IR/PassManager.h"
54#include "llvm/MC/MCAsmInfo.h"
55#include "llvm/MC/MCContext.h"
56#include "llvm/MC/MCExpr.h"
57#include "llvm/MC/MCInst.h"
61#include "llvm/MC/MCStreamer.h"
62#include "llvm/MC/MCSymbol.h"
63#include "llvm/MC/MCValue.h"
72#include <cassert>
73#include <cstdint>
74#include <map>
75#include <memory>
76
77using namespace llvm;
79
80#define DEBUG_TYPE "AArch64AsmPrinter"
81
82// Doesn't count FPR128 ZCZ instructions which are handled
83// by TableGen pattern matching
84STATISTIC(NumZCZeroingInstrsFPR,
85 "Number of zero-cycle FPR zeroing instructions expanded from "
86 "canonical pseudo instructions");
87
88namespace {
89
90class AArch64AsmPrinter : public AsmPrinter {
91 AArch64MCInstLower MCInstLowering;
92 FaultMaps FM;
93 const AArch64Subtarget *STI;
94 bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false;
95 bool PtrauthInitFini = false;
96 bool PtrauthInitFiniAddressDisc = false;
97#ifndef NDEBUG
98 unsigned InstsEmitted;
99#endif
100 bool EnableImportCallOptimization = false;
102 SectionToImportedFunctionCalls;
103 unsigned PAuthIFuncNextUniqueID = 1;
104
105public:
106 static char ID;
107
108 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
109 : AsmPrinter(TM, std::move(Streamer), ID),
110 MCInstLowering(OutContext, *this), FM(*this) {}
111
112 StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
113
114 /// Wrapper for MCInstLowering.lowerOperand() for the
115 /// tblgen'erated pseudo lowering.
116 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
117 return MCInstLowering.lowerOperand(MO, MCOp);
118 }
119
120 const MCExpr *lowerConstantPtrAuth(const ConstantPtrAuth &CPA) override;
121
122 const MCExpr *lowerBlockAddressConstant(const BlockAddress &BA) override;
123
124 void emitStartOfAsmFile(Module &M) override;
125 void emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
126 ArrayRef<unsigned> JumpTableIndices) override;
127 std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
129 getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
130 const MCSymbol *BranchLabel) const override;
131
132 void emitFunctionEntryLabel() override;
133
134 void emitXXStructor(const DataLayout &DL, const Constant *CV) override;
135
136 void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
137
138 void LowerHardenedBRJumpTable(const MachineInstr &MI);
139
140 void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI);
141
142 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
143 const MachineInstr &MI);
144 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
145 const MachineInstr &MI);
146 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
147 const MachineInstr &MI);
148 void LowerFAULTING_OP(const MachineInstr &MI);
149
150 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
151 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
152 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
153 void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
154
155 typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
156 HwasanMemaccessTuple;
157 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
158 void LowerKCFI_CHECK(const MachineInstr &MI);
159 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
160 void emitHwasanMemaccessSymbols(Module &M);
161
162 void emitSled(const MachineInstr &MI, SledKind Kind);
163
164 // Returns whether Reg may be used to store sensitive temporary values when
165 // expanding PtrAuth pseudos. Some OSes may take extra care to protect a
166 // small subset of GPRs on context switches - use these registers then.
167 //
168 // If there are no preferred registers, returns true for any Reg.
169 bool isPtrauthRegSafe(Register Reg) const {
170 if (STI->isX16X17Safer())
171 return Reg == AArch64::X16 || Reg == AArch64::X17;
172
173 return true;
174 }
175
176 // Emit the sequence for BRA/BLRA (authenticate + branch/call).
177 void emitPtrauthBranch(const MachineInstr *MI);
178
179 void emitPtrauthCheckAuthenticatedValue(Register TestedReg,
180 Register ScratchReg,
183 const MCSymbol *OnFailure = nullptr);
184
185 // Check authenticated LR before tail calling.
186 void emitPtrauthTailCallHardening(const MachineInstr *TC);
187
188 struct PtrAuthSchema {
189 static PtrAuthSchema CreateImmReg(AArch64PACKey::ID Key, uint64_t IntDisc,
190 const MachineOperand &AddrDiscOp);
191 static PtrAuthSchema CreateRegReg(AArch64PACKey::ID Key, Register AddrDisc,
192 Register PCDisc);
193
195 uint64_t IntDisc;
196 Register AddrDisc;
197 bool AddrDiscIsKilled;
198 Register PCDisc;
199
200 bool addrDiscIsKilledAndNoneOf(std::initializer_list<Register> Regs) {
201 return AddrDiscIsKilled && !llvm::is_contained(Regs, AddrDisc);
202 }
203 };
204
205 // Helper for emitting AUTRELLOADPAC: increment Pointer by Addend and then by
206 // a 32-bit signed value loaded from memory. The instructions emitted are
207 //
208 // ldrsw Scratch, [Pointer, #Addend]!
209 // add Pointer, Pointer, Scratch
210 //
211 // for small Addend value, with longer sequences required for wider Addend.
212 void emitPtrauthApplyIndirectAddend(Register Pointer, Register Scratch,
213 int64_t Addend);
214
215 // Emit the sequence for AUT or AUTPAC (or their PC-blending variants).
216 // Addend is only used for AUTRELLOADPAC.
217 void emitPtrauthAuthResign(Register Pointer, Register Scratch,
218 PtrAuthSchema AuthSchema,
219 std::optional<PtrAuthSchema> SignSchema,
220 std::optional<int64_t> Addend, Value *DS);
221
222 // Emit R_AARCH64_PATCHINST, the deactivation symbol relocation. Returns true
223 // if no instruction should be emitted because the deactivation symbol is
224 // defined in the current module so this function emitted a NOP instead.
225 bool emitDeactivationSymbolRelocation(Value *DS);
226
227 // Emit the sequence for PAC.
228 void emitPtrauthSign(const MachineInstr *MI);
229
230 // Emit the sequence to compute the discriminator.
231 //
232 // The Scratch register passed to this function must be safe, as returned by
233 // isPtrauthRegSafe(ScratchReg).
234 //
235 // The returned register is either ScratchReg, AddrDisc, or XZR. Furthermore,
236 // it is guaranteed to be safe (or XZR), with the only exception of
237 // passing-through an *unmodified* unsafe AddrDisc register.
238 //
239 // If the expanded pseudo is allowed to clobber AddrDisc register, setting
240 // MayClobberAddrDisc may save one MOV instruction, provided
241 // isPtrauthRegSafe(AddrDisc) is true:
242 //
243 // mov x17, x16
244 // movk x17, #1234, lsl #48
245 // ; x16 is not used anymore
246 //
247 // can be replaced by
248 //
249 // movk x16, #1234, lsl #48
250 Register emitPtrauthDiscriminator(uint64_t Disc, Register AddrDisc,
251 Register ScratchReg,
252 bool MayClobberAddrDisc = false);
253
254 // Emit the sequence for LOADauthptrstatic
255 void LowerLOADauthptrstatic(const MachineInstr &MI);
256
257 // Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or
258 // adrp-add followed by PAC sign)
259 void LowerMOVaddrPAC(const MachineInstr &MI);
260
261 // Emit the sequence for LOADgotAUTH (load signed pointer from signed ELF GOT
262 // and authenticate it with, if FPAC bit is not set, check+trap sequence after
263 // authenticating)
264 void LowerLOADgotAUTH(const MachineInstr &MI);
265
266 void emitAddImm(MCRegister Val, int64_t Addend, MCRegister Tmp);
267 void emitAddress(MCRegister Reg, const MCExpr *Expr, MCRegister Tmp,
268 bool DSOLocal, const MCSubtargetInfo &STI);
269
270 const MCExpr *emitPAuthRelocationAsIRelative(
271 const MCExpr *Target, uint64_t Disc, AArch64PACKey::ID KeyID,
272 bool HasAddressDiversity, bool IsDSOLocal, const MCExpr *DSExpr);
273
274 /// tblgen'erated driver function for lowering simple MI->MC
275 /// pseudo instructions.
276 bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
277
278 // Emit Build Attributes
279 void emitAttributes(unsigned Flags, uint64_t PAuthABIPlatform,
280 uint64_t PAuthABIVersion, AArch64TargetStreamer *TS);
281
282 // Emit expansion of Compare-and-branch pseudo instructions
283 void emitCBPseudoExpansion(const MachineInstr *MI);
284
285 // Emit expansion of atomic store with hint pseudo instructions
286 void emitAtomicHintPseudoExpansion(const MachineInstr *MI);
287 void emitAtomicHintPseudoExpansionRO(const MachineInstr *MI);
288 void emitAtomicHintPseudoExpansionImm(const MachineInstr *MI);
289
290 // Emit expansion of atomic fetch with hint pseudo instructions
291 void emitAtomicFetchHintPseudoExpansion(const MachineInstr *MI);
292
293 void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
294 void EmitToStreamer(const MCInst &Inst) {
295 EmitToStreamer(*OutStreamer, Inst);
296 }
297
298 void emitInstruction(const MachineInstr *MI) override;
299
300 void emitFunctionHeaderComment() override;
301
302 void getAnalysisUsage(AnalysisUsage &AU) const override {
304 AU.setPreservesAll();
305 }
306
307 bool runOnMachineFunction(MachineFunction &MF) override {
308 if (auto *PSIW = getAnalysisIfAvailable<ProfileSummaryInfoWrapperPass>())
309 PSI = &PSIW->getPSI();
310 if (auto *SDPIW =
311 getAnalysisIfAvailable<StaticDataProfileInfoWrapperPass>())
312 SDPI = &SDPIW->getStaticDataProfileInfo();
313
314 AArch64FI = MF.getInfo<AArch64FunctionInfo>();
315 STI = &MF.getSubtarget<AArch64Subtarget>();
316
317 SetupMachineFunction(MF);
318
319 if (STI->isTargetCOFF()) {
320 bool Local = MF.getFunction().hasLocalLinkage();
323 int Type =
325
326 OutStreamer->beginCOFFSymbolDef(CurrentFnSym);
327 OutStreamer->emitCOFFSymbolStorageClass(Scl);
328 OutStreamer->emitCOFFSymbolType(Type);
329 OutStreamer->endCOFFSymbolDef();
330 }
331
332 // Emit the rest of the function body.
333 emitFunctionBody();
334
335 // Emit the XRay table for this function.
336 emitXRayTable();
337
338 // We didn't modify anything.
339 return false;
340 }
341
342 const MCExpr *lowerConstant(const Constant *CV,
343 const Constant *BaseCV = nullptr,
344 uint64_t Offset = 0) override;
345
346private:
347 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
348 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
349 bool printAsmRegInClass(const MachineOperand &MO,
350 const TargetRegisterClass *RC, unsigned AltName,
351 raw_ostream &O);
352
353 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
354 const char *ExtraCode, raw_ostream &O) override;
355 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
356 const char *ExtraCode, raw_ostream &O) override;
357
358 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
359
360 void emitFunctionBodyEnd() override;
361 void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
362
363 MCSymbol *GetCPISymbol(unsigned CPID) const override;
364 void emitEndOfAsmFile(Module &M) override;
365
366 AArch64FunctionInfo *AArch64FI = nullptr;
367
368 /// Emit the LOHs contained in AArch64FI.
369 void emitLOHs();
370
371 void emitMovXReg(Register Dest, Register Src);
372 void emitMOVZ(Register Dest, uint64_t Imm, unsigned Shift);
373 void emitMOVK(Register Dest, uint64_t Imm, unsigned Shift);
374
375 void emitAUT(AArch64PACKey::ID Key, Register Pointer, Register Disc);
376 void emitPAC(AArch64PACKey::ID Key, Register Pointer, Register Disc);
377 void emitBLRA(bool IsCall, AArch64PACKey::ID Key, Register Target,
378 Register Disc);
379
380 /// Emit instruction to set float register to zero.
381 void emitFMov0(const MachineInstr &MI);
382 void emitFMov0AsFMov(const MachineInstr &MI, Register DestReg);
383
384 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
385
386 MInstToMCSymbol LOHInstToLabel;
387
388 bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
389 return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
390 }
391
392 const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
393 assert(STI);
394 return STI;
395 }
396 void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
397 MCSymbol *LazyPointer) override;
398 void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
399 MCSymbol *LazyPointer) override;
400
401 /// Checks if this instruction is part of a sequence that is eligle for import
402 /// call optimization and, if so, records it to be emitted in the import call
403 /// section.
404 void recordIfImportCall(const MachineInstr *BranchInst);
405};
406
407} // end anonymous namespace
408
409// Get boolean module flag (0 or 1), treating absent flag as having value 0.
411 Metadata *Flag = M.getModuleFlag(Name);
412 if (!Flag)
413 return false;
414
415 uint64_t Value = mdconst::extract<ConstantInt>(Flag)->getZExtValue();
416 assert((Value == 0 || Value == 1) && "Boolean flag is expected, if present");
417 return Value;
418}
419
420void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
421 const Triple &TT = M.getTargetTriple();
422
423 if (TT.isOSBinFormatCOFF()) {
424 emitCOFFFeatureSymbol(M);
425 emitCOFFReplaceableFunctionData(M);
426
427 if (M.getModuleFlag("import-call-optimization"))
428 EnableImportCallOptimization = true;
429 }
430
431 PtrauthInitFini = getOptionalBooleanModuleFlag(M, "ptrauth-init-fini");
432 PtrauthInitFiniAddressDisc = getOptionalBooleanModuleFlag(
433 M, "ptrauth-init-fini-address-discrimination");
434
435 if (!TT.isOSBinFormatELF())
436 return;
437
438 // For emitting build attributes and .note.gnu.property section
439 auto *TS =
440 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
441 // Assemble feature flags that may require creation of build attributes and a
442 // note section.
443 unsigned BAFlags = 0;
444 unsigned GNUFlags = 0;
445 if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
446 M.getModuleFlag("branch-target-enforcement"))) {
447 if (!BTE->isZero()) {
448 BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_BTI_Flag;
450 }
451 }
452
453 if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
454 M.getModuleFlag("guarded-control-stack"))) {
455 if (!GCS->isZero()) {
456 BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_GCS_Flag;
458 }
459 }
460
461 if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
462 M.getModuleFlag("sign-return-address"))) {
463 if (!Sign->isZero()) {
464 BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_PAC_Flag;
466 }
467 }
468
469 uint64_t PAuthABIPlatform = -1;
470 if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
471 M.getModuleFlag("aarch64-elf-pauthabi-platform"))) {
472 PAuthABIPlatform = PAP->getZExtValue();
473 }
474
475 uint64_t PAuthABIVersion = -1;
476 if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
477 M.getModuleFlag("aarch64-elf-pauthabi-version"))) {
478 PAuthABIVersion = PAV->getZExtValue();
479 }
480
481 // For LLVM_LINUX experimental platform, version value of 0 means no PAuth
482 // support. Do not emit corresponding PAuthABI GNU property note and AArch64
483 // build attributes for this case to keep Linux binaries not using PAuth
484 // unaffected.
485 if (PAuthABIPlatform == ELF::AARCH64_PAUTH_PLATFORM_LLVM_LINUX &&
486 PAuthABIVersion == 0) {
487 PAuthABIPlatform = uint64_t(-1);
488 PAuthABIVersion = uint64_t(-1);
489 }
490
491 // Emit AArch64 Build Attributes
492 emitAttributes(BAFlags, PAuthABIPlatform, PAuthABIVersion, TS);
493 // Emit a .note.gnu.property section with the flags.
494 TS->emitNoteSection(GNUFlags, PAuthABIPlatform, PAuthABIVersion);
495}
496
497void AArch64AsmPrinter::emitFunctionHeaderComment() {
498 const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>();
499 std::optional<std::string> OutlinerString = FI->getOutliningStyle();
500 if (OutlinerString != std::nullopt)
501 OutStreamer->getCommentOS() << ' ' << OutlinerString;
502}
503
504void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
505{
506 const Function &F = MF->getFunction();
507 if (F.hasFnAttribute("patchable-function-entry")) {
508 unsigned Num;
509 if (F.getFnAttribute("patchable-function-entry")
510 .getValueAsString()
511 .getAsInteger(10, Num))
512 return;
513 emitNops(Num);
514 return;
515 }
516
517 emitSled(MI, SledKind::FUNCTION_ENTER);
518}
519
520void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
521 emitSled(MI, SledKind::FUNCTION_EXIT);
522}
523
524void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
525 emitSled(MI, SledKind::TAIL_CALL);
526}
527
528void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
529 static const int8_t NoopsInSledCount = 7;
530 // We want to emit the following pattern:
531 //
532 // .Lxray_sled_N:
533 // ALIGN
534 // B #32
535 // ; 7 NOP instructions (28 bytes)
536 // .tmpN
537 //
538 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
539 // over the full 32 bytes (8 instructions) with the following pattern:
540 //
541 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
542 // LDR W17, #12 ; W17 := function ID
543 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
544 // BLR X16 ; call the tracing trampoline
545 // ;DATA: 32 bits of function ID
546 // ;DATA: lower 32 bits of the address of the trampoline
547 // ;DATA: higher 32 bits of the address of the trampoline
548 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
549 //
550 OutStreamer->emitCodeAlignment(Align(4), getSubtargetInfo());
551 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
552 OutStreamer->emitLabel(CurSled);
553 auto Target = OutContext.createTempSymbol();
554
555 // Emit "B #32" instruction, which jumps over the next 28 bytes.
556 // The operand has to be the number of 4-byte instructions to jump over,
557 // including the current instruction.
558 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
559
560 for (int8_t I = 0; I < NoopsInSledCount; I++)
561 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::NOP));
562
563 OutStreamer->emitLabel(Target);
564 recordSled(CurSled, MI, Kind, 2);
565}
566
567void AArch64AsmPrinter::emitAttributes(unsigned Flags,
568 uint64_t PAuthABIPlatform,
569 uint64_t PAuthABIVersion,
570 AArch64TargetStreamer *TS) {
571
572 PAuthABIPlatform = (uint64_t(-1) == PAuthABIPlatform) ? 0 : PAuthABIPlatform;
573 PAuthABIVersion = (uint64_t(-1) == PAuthABIVersion) ? 0 : PAuthABIVersion;
574
575 if (PAuthABIPlatform || PAuthABIVersion) {
579 AArch64BuildAttributes::SubsectionOptional::REQUIRED,
580 AArch64BuildAttributes::SubsectionType::ULEB128);
584 PAuthABIPlatform, "");
588 "");
589 }
590
591 unsigned BTIValue =
593 unsigned PACValue =
595 unsigned GCSValue =
597
598 if (BTIValue || PACValue || GCSValue) {
602 AArch64BuildAttributes::SubsectionOptional::OPTIONAL,
603 AArch64BuildAttributes::SubsectionType::ULEB128);
613 }
614}
615
616// Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
617// (built-in functions __xray_customevent/__xray_typedevent).
618//
619// .Lxray_event_sled_N:
620// b 1f
621// save x0 and x1 (and also x2 for TYPED_EVENT_CALL)
622// set up x0 and x1 (and also x2 for TYPED_EVENT_CALL)
623// bl __xray_CustomEvent or __xray_TypedEvent
624// restore x0 and x1 (and also x2 for TYPED_EVENT_CALL)
625// 1:
626//
627// There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL.
628//
629// Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT.
630// After patching, b .+N will become a nop.
631void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
632 bool Typed) {
633 auto &O = *OutStreamer;
634 MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
635 O.emitLabel(CurSled);
636 bool MachO = MMI->getModule()->getTargetTriple().isOSBinFormatMachO();
637 auto *Sym = MCSymbolRefExpr::create(
638 OutContext.getOrCreateSymbol(
639 Twine(MachO ? "_" : "") +
640 (Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")),
641 OutContext);
642 if (Typed) {
643 O.AddComment("Begin XRay typed event");
644 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9));
645 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
646 .addReg(AArch64::SP)
647 .addReg(AArch64::X0)
648 .addReg(AArch64::X1)
649 .addReg(AArch64::SP)
650 .addImm(-4));
651 EmitToStreamer(O, MCInstBuilder(AArch64::STRXui)
652 .addReg(AArch64::X2)
653 .addReg(AArch64::SP)
654 .addImm(2));
655 emitMovXReg(AArch64::X0, MI.getOperand(0).getReg());
656 emitMovXReg(AArch64::X1, MI.getOperand(1).getReg());
657 emitMovXReg(AArch64::X2, MI.getOperand(2).getReg());
658 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
659 EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui)
660 .addReg(AArch64::X2)
661 .addReg(AArch64::SP)
662 .addImm(2));
663 O.AddComment("End XRay typed event");
664 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
665 .addReg(AArch64::SP)
666 .addReg(AArch64::X0)
667 .addReg(AArch64::X1)
668 .addReg(AArch64::SP)
669 .addImm(4));
670
671 recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2);
672 } else {
673 O.AddComment("Begin XRay custom event");
674 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6));
675 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
676 .addReg(AArch64::SP)
677 .addReg(AArch64::X0)
678 .addReg(AArch64::X1)
679 .addReg(AArch64::SP)
680 .addImm(-2));
681 emitMovXReg(AArch64::X0, MI.getOperand(0).getReg());
682 emitMovXReg(AArch64::X1, MI.getOperand(1).getReg());
683 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
684 O.AddComment("End XRay custom event");
685 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
686 .addReg(AArch64::SP)
687 .addReg(AArch64::X0)
688 .addReg(AArch64::X1)
689 .addReg(AArch64::SP)
690 .addImm(2));
691
692 recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2);
693 }
694}
695
696void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
697 Register AddrReg = MI.getOperand(0).getReg();
698 assert(std::next(MI.getIterator())->isCall() &&
699 "KCFI_CHECK not followed by a call instruction");
700 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
701 "KCFI_CHECK call target doesn't match call operand");
702
703 // Default to using the intra-procedure-call temporary registers for
704 // comparing the hashes.
705 unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
706 if (AddrReg == AArch64::XZR) {
707 // Checking XZR makes no sense. Instead of emitting a load, zero
708 // ScratchRegs[0] and use it for the ESR AddrIndex below.
709 AddrReg = getXRegFromWReg(ScratchRegs[0]);
710 emitMovXReg(AddrReg, AArch64::XZR);
711 } else {
712 // If one of the scratch registers is used for the call target (e.g.
713 // with AArch64::TCRETURNriBTI), we can clobber another caller-saved
714 // temporary register instead (in this case, AArch64::W9) as the check
715 // is immediately followed by the call instruction.
716 for (auto &Reg : ScratchRegs) {
717 if (Reg == getWRegFromXReg(AddrReg)) {
718 Reg = AArch64::W9;
719 break;
720 }
721 }
722 assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
723 "Invalid scratch registers for KCFI_CHECK");
724
725 // Adjust the offset for patchable-function-prefix. This assumes that
726 // patchable-function-prefix is the same for all functions.
727 int64_t PrefixNops =
728 MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
729 "patchable-function-prefix");
730
731 // Load the target function type hash.
732 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
733 .addReg(ScratchRegs[0])
734 .addReg(AddrReg)
735 .addImm(-(PrefixNops * 4 + 4)));
736 }
737
738 // Load the expected type hash.
739 const int64_t Type = MI.getOperand(1).getImm();
740 emitMOVK(ScratchRegs[1], Type & 0xFFFF, 0);
741 emitMOVK(ScratchRegs[1], (Type >> 16) & 0xFFFF, 16);
742
743 // Compare the hashes and trap if there's a mismatch.
744 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs)
745 .addReg(AArch64::WZR)
746 .addReg(ScratchRegs[0])
747 .addReg(ScratchRegs[1])
748 .addImm(0));
749
750 MCSymbol *Pass = OutContext.createTempSymbol();
751 EmitToStreamer(*OutStreamer,
752 MCInstBuilder(AArch64::Bcc)
753 .addImm(AArch64CC::EQ)
754 .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
755
756 // The base ESR is 0x8000 and the register information is encoded in bits
757 // 0-9 as follows:
758 // - 0-4: n, where the register Xn contains the target address
759 // - 5-9: m, where the register Wm contains the expected type hash
760 // Where n, m are in [0, 30].
761 unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
762 unsigned AddrIndex;
763 switch (AddrReg) {
764 default:
765 AddrIndex = AddrReg - AArch64::X0;
766 break;
767 case AArch64::FP:
768 AddrIndex = 29;
769 break;
770 case AArch64::LR:
771 AddrIndex = 30;
772 break;
773 }
774
775 assert(AddrIndex < 31 && TypeIndex < 31);
776
777 unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
778 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR));
779 OutStreamer->emitLabel(Pass);
780}
781
782void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
783 Register Reg = MI.getOperand(0).getReg();
784
785 // The HWASan pass won't emit a CHECK_MEMACCESS intrinsic with a pointer
786 // statically known to be zero. However, conceivably, the HWASan pass may
787 // encounter a "cannot currently statically prove to be null" pointer (and is
788 // therefore unable to omit the intrinsic) that later optimization passes
789 // convert into a statically known-null pointer.
790 if (Reg == AArch64::XZR)
791 return;
792
793 bool IsShort =
794 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
795 (MI.getOpcode() ==
796 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
797 uint32_t AccessInfo = MI.getOperand(1).getImm();
798 bool IsFixedShadow =
799 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
800 (MI.getOpcode() ==
801 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
802 uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0;
803
804 MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
805 Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
806 if (!Sym) {
807 // FIXME: Make this work on non-ELF.
808 if (!TM.getTargetTriple().isOSBinFormatELF())
809 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
810
811 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
812 utostr(AccessInfo);
813 if (IsFixedShadow)
814 SymName += "_fixed_" + utostr(FixedShadowOffset);
815 if (IsShort)
816 SymName += "_short_v2";
817 Sym = OutContext.getOrCreateSymbol(SymName);
818 }
819
820 EmitToStreamer(*OutStreamer,
821 MCInstBuilder(AArch64::BL)
822 .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
823}
824
825void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
826 if (HwasanMemaccessSymbols.empty())
827 return;
828
829 const Triple &TT = M.getTargetTriple();
830 assert(TT.isOSBinFormatELF());
831 // AArch64Subtarget is huge, so heap allocate it so we don't run out of stack
832 // space.
833 auto STI = std::make_unique<AArch64Subtarget>(
834 TT, TM.getTargetCPU(), TM.getTargetCPU(), TM.getTargetFeatureString(), TM,
835 true);
836 this->STI = STI.get();
837
838 MCSymbol *HwasanTagMismatchV1Sym =
839 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
840 MCSymbol *HwasanTagMismatchV2Sym =
841 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
842
843 const MCSymbolRefExpr *HwasanTagMismatchV1Ref =
844 MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext);
845 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
846 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
847
848 for (auto &P : HwasanMemaccessSymbols) {
849 unsigned Reg = std::get<0>(P.first);
850 bool IsShort = std::get<1>(P.first);
851 uint32_t AccessInfo = std::get<2>(P.first);
852 bool IsFixedShadow = std::get<3>(P.first);
853 uint64_t FixedShadowOffset = std::get<4>(P.first);
854 const MCSymbolRefExpr *HwasanTagMismatchRef =
855 IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
856 MCSymbol *Sym = P.second;
857
858 bool HasMatchAllTag =
859 (AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1;
860 uint8_t MatchAllTag =
861 (AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff;
862 unsigned Size =
863 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
864 bool CompileKernel =
865 (AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1;
866
867 OutStreamer->switchSection(OutContext.getELFSection(
868 ".text.hot", ELF::SHT_PROGBITS,
870 /*IsComdat=*/true));
871
872 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
873 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
874 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
875 OutStreamer->emitLabel(Sym);
876
877 EmitToStreamer(MCInstBuilder(AArch64::SBFMXri)
878 .addReg(AArch64::X16)
879 .addReg(Reg)
880 .addImm(4)
881 .addImm(55));
882
883 if (IsFixedShadow) {
884 // Aarch64 makes it difficult to embed large constants in the code.
885 // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit
886 // left-shift option in the MOV instruction. Combined with the 16-bit
887 // immediate, this is enough to represent any offset up to 2**48.
888 emitMOVZ(AArch64::X17, FixedShadowOffset >> 32, 32);
889 EmitToStreamer(MCInstBuilder(AArch64::LDRBBroX)
890 .addReg(AArch64::W16)
891 .addReg(AArch64::X17)
892 .addReg(AArch64::X16)
893 .addImm(0)
894 .addImm(0));
895 } else {
896 EmitToStreamer(MCInstBuilder(AArch64::LDRBBroX)
897 .addReg(AArch64::W16)
898 .addReg(IsShort ? AArch64::X20 : AArch64::X9)
899 .addReg(AArch64::X16)
900 .addImm(0)
901 .addImm(0));
902 }
903
904 EmitToStreamer(MCInstBuilder(AArch64::SUBSXrs)
905 .addReg(AArch64::XZR)
906 .addReg(AArch64::X16)
907 .addReg(Reg)
909 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
910 EmitToStreamer(MCInstBuilder(AArch64::Bcc)
911 .addImm(AArch64CC::NE)
913 HandleMismatchOrPartialSym, OutContext)));
914 MCSymbol *ReturnSym = OutContext.createTempSymbol();
915 OutStreamer->emitLabel(ReturnSym);
916 EmitToStreamer(MCInstBuilder(AArch64::RET).addReg(AArch64::LR));
917 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
918
919 if (HasMatchAllTag) {
920 EmitToStreamer(MCInstBuilder(AArch64::UBFMXri)
921 .addReg(AArch64::X17)
922 .addReg(Reg)
923 .addImm(56)
924 .addImm(63));
925 EmitToStreamer(MCInstBuilder(AArch64::SUBSXri)
926 .addReg(AArch64::XZR)
927 .addReg(AArch64::X17)
928 .addImm(MatchAllTag)
929 .addImm(0));
930 EmitToStreamer(
931 MCInstBuilder(AArch64::Bcc)
932 .addImm(AArch64CC::EQ)
933 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)));
934 }
935
936 if (IsShort) {
937 EmitToStreamer(MCInstBuilder(AArch64::SUBSWri)
938 .addReg(AArch64::WZR)
939 .addReg(AArch64::W16)
940 .addImm(15)
941 .addImm(0));
942 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
943 EmitToStreamer(
944 MCInstBuilder(AArch64::Bcc)
945 .addImm(AArch64CC::HI)
946 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)));
947
948 EmitToStreamer(MCInstBuilder(AArch64::ANDXri)
949 .addReg(AArch64::X17)
950 .addReg(Reg)
951 .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)));
952 if (Size != 1)
953 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
954 .addReg(AArch64::X17)
955 .addReg(AArch64::X17)
956 .addImm(Size - 1)
957 .addImm(0));
958 EmitToStreamer(MCInstBuilder(AArch64::SUBSWrs)
959 .addReg(AArch64::WZR)
960 .addReg(AArch64::W16)
961 .addReg(AArch64::W17)
962 .addImm(0));
963 EmitToStreamer(
964 MCInstBuilder(AArch64::Bcc)
965 .addImm(AArch64CC::LS)
966 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)));
967
968 EmitToStreamer(MCInstBuilder(AArch64::ORRXri)
969 .addReg(AArch64::X16)
970 .addReg(Reg)
971 .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)));
972 EmitToStreamer(MCInstBuilder(AArch64::LDRBBui)
973 .addReg(AArch64::W16)
974 .addReg(AArch64::X16)
975 .addImm(0));
976 EmitToStreamer(
977 MCInstBuilder(AArch64::SUBSXrs)
978 .addReg(AArch64::XZR)
979 .addReg(AArch64::X16)
980 .addReg(Reg)
982 EmitToStreamer(
983 MCInstBuilder(AArch64::Bcc)
984 .addImm(AArch64CC::EQ)
985 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)));
986
987 OutStreamer->emitLabel(HandleMismatchSym);
988 }
989
990 EmitToStreamer(MCInstBuilder(AArch64::STPXpre)
991 .addReg(AArch64::SP)
992 .addReg(AArch64::X0)
993 .addReg(AArch64::X1)
994 .addReg(AArch64::SP)
995 .addImm(-32));
996 EmitToStreamer(MCInstBuilder(AArch64::STPXi)
997 .addReg(AArch64::FP)
998 .addReg(AArch64::LR)
999 .addReg(AArch64::SP)
1000 .addImm(29));
1001
1002 if (Reg != AArch64::X0)
1003 emitMovXReg(AArch64::X0, Reg);
1004 emitMOVZ(AArch64::X1, AccessInfo & HWASanAccessInfo::RuntimeMask, 0);
1005
1006 if (CompileKernel) {
1007 // The Linux kernel's dynamic loader doesn't support GOT relative
1008 // relocations, but it doesn't support late binding either, so just call
1009 // the function directly.
1010 EmitToStreamer(MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef));
1011 } else {
1012 // Intentionally load the GOT entry and branch to it, rather than possibly
1013 // late binding the function, which may clobber the registers before we
1014 // have a chance to save them.
1015 EmitToStreamer(MCInstBuilder(AArch64::ADRP)
1016 .addReg(AArch64::X16)
1017 .addExpr(MCSpecifierExpr::create(HwasanTagMismatchRef,
1019 OutContext)));
1020 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
1021 .addReg(AArch64::X16)
1022 .addReg(AArch64::X16)
1023 .addExpr(MCSpecifierExpr::create(HwasanTagMismatchRef,
1025 OutContext)));
1026 EmitToStreamer(MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
1027 }
1028 }
1029 this->STI = nullptr;
1030}
1031
1032static void emitAuthenticatedPointer(MCStreamer &OutStreamer,
1033 MCSymbol *StubLabel,
1034 const MCExpr *StubAuthPtrRef) {
1035 // sym$auth_ptr$key$disc:
1036 OutStreamer.emitLabel(StubLabel);
1037 OutStreamer.emitValue(StubAuthPtrRef, /*size=*/8);
1038}
1039
1040void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
1041 emitHwasanMemaccessSymbols(M);
1042
1043 const Triple &TT = M.getTargetTriple();
1044 if (TT.isOSBinFormatMachO()) {
1045 // Output authenticated pointers as indirect symbols, if we have any.
1046 MachineModuleInfoMachO &MMIMacho =
1047 MMI->getObjFileInfo<MachineModuleInfoMachO>();
1048
1049 auto Stubs = MMIMacho.getAuthGVStubList();
1050
1051 if (!Stubs.empty()) {
1052 // Switch to the "__auth_ptr" section.
1053 OutStreamer->switchSection(
1054 OutContext.getMachOSection("__DATA", "__auth_ptr", MachO::S_REGULAR,
1056 emitAlignment(Align(8));
1057
1058 for (const auto &Stub : Stubs)
1059 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
1060
1061 OutStreamer->addBlankLine();
1062 }
1063
1064 // Funny Darwin hack: This flag tells the linker that no global symbols
1065 // contain code that falls through to other global symbols (e.g. the obvious
1066 // implementation of multiple entry points). If this doesn't occur, the
1067 // linker can safely perform dead code stripping. Since LLVM never
1068 // generates code that does this, it is always safe to set.
1069 OutStreamer->emitSubsectionsViaSymbols();
1070 }
1071
1072 if (TT.isOSBinFormatELF()) {
1073 // Output authenticated pointers as indirect symbols, if we have any.
1074 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
1075
1076 auto Stubs = MMIELF.getAuthGVStubList();
1077
1078 if (!Stubs.empty()) {
1079 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1080 OutStreamer->switchSection(TLOF.getDataSection());
1081 emitAlignment(Align(8));
1082
1083 for (const auto &Stub : Stubs)
1084 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
1085
1086 OutStreamer->addBlankLine();
1087 }
1088
1089 // With signed ELF GOT enabled, the linker looks at the symbol type to
1090 // choose between keys IA (for STT_FUNC) and DA (for other types). Symbols
1091 // for functions not defined in the module have STT_NOTYPE type by default.
1092 // This makes linker to emit signing schema with DA key (instead of IA) for
1093 // corresponding R_AARCH64_AUTH_GLOB_DAT dynamic reloc. To avoid that, force
1094 // all function symbols used in the module to have STT_FUNC type. See
1095 // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
1096 const auto *PtrAuthELFGOTFlag = mdconst::extract_or_null<ConstantInt>(
1097 M.getModuleFlag("ptrauth-elf-got"));
1098 if (PtrAuthELFGOTFlag && PtrAuthELFGOTFlag->getZExtValue() == 1)
1099 for (const GlobalValue &GV : M.global_values())
1100 if (!GV.use_empty() && isa<Function>(GV) &&
1101 !GV.getName().starts_with("llvm."))
1102 OutStreamer->emitSymbolAttribute(getSymbol(&GV),
1104 }
1105
1106 // Emit stack and fault map information.
1108
1109 // If import call optimization is enabled, emit the appropriate section.
1110 // We do this whether or not we recorded any import calls.
1111 if (EnableImportCallOptimization && TT.isOSBinFormatCOFF()) {
1112 OutStreamer->switchSection(getObjFileLowering().getImportCallSection());
1113
1114 // Section always starts with some magic.
1115 constexpr char ImpCallMagic[12] = "Imp_Call_V1";
1116 OutStreamer->emitBytes(StringRef{ImpCallMagic, sizeof(ImpCallMagic)});
1117
1118 // Layout of this section is:
1119 // Per section that contains calls to imported functions:
1120 // uint32_t SectionSize: Size in bytes for information in this section.
1121 // uint32_t Section Number
1122 // Per call to imported function in section:
1123 // uint32_t Kind: the kind of imported function.
1124 // uint32_t BranchOffset: the offset of the branch instruction in its
1125 // parent section.
1126 // uint32_t TargetSymbolId: the symbol id of the called function.
1127 for (auto &[Section, CallsToImportedFuncs] :
1128 SectionToImportedFunctionCalls) {
1129 unsigned SectionSize =
1130 sizeof(uint32_t) * (2 + 3 * CallsToImportedFuncs.size());
1131 OutStreamer->emitInt32(SectionSize);
1132 OutStreamer->emitCOFFSecNumber(Section->getBeginSymbol());
1133 for (auto &[CallsiteSymbol, CalledSymbol] : CallsToImportedFuncs) {
1134 // Kind is always IMAGE_REL_ARM64_DYNAMIC_IMPORT_CALL (0x13).
1135 OutStreamer->emitInt32(0x13);
1136 OutStreamer->emitCOFFSecOffset(CallsiteSymbol);
1137 OutStreamer->emitCOFFSymbolIndex(CalledSymbol);
1138 }
1139 }
1140 }
1141}
1142
1143void AArch64AsmPrinter::emitLOHs() {
1145
1146 for (const auto &D : AArch64FI->getLOHContainer()) {
1147 for (const MachineInstr *MI : D.getArgs()) {
1148 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
1149 assert(LabelIt != LOHInstToLabel.end() &&
1150 "Label hasn't been inserted for LOH related instruction");
1151 MCArgs.push_back(LabelIt->second);
1152 }
1153 OutStreamer->emitLOHDirective(D.getKind(), MCArgs);
1154 MCArgs.clear();
1155 }
1156}
1157
1158void AArch64AsmPrinter::emitFunctionBodyEnd() {
1159 if (!AArch64FI->getLOHRelated().empty())
1160 emitLOHs();
1161}
1162
1163/// GetCPISymbol - Return the symbol for the specified constant pool entry.
1164MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
1165 // Darwin uses a linker-private symbol name for constant-pools (to
1166 // avoid addends on the relocation?), ELF has no such concept and
1167 // uses a normal private symbol.
1168 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
1169 return OutContext.getOrCreateSymbol(
1170 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
1171 Twine(getFunctionNumber()) + "_" + Twine(CPID));
1172
1173 return AsmPrinter::GetCPISymbol(CPID);
1174}
1175
1176void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
1177 raw_ostream &O) {
1178 const MachineOperand &MO = MI->getOperand(OpNum);
1179 switch (MO.getType()) {
1180 default:
1181 llvm_unreachable("<unknown operand type>");
1183 Register Reg = MO.getReg();
1185 assert(!MO.getSubReg() && "Subregs should be eliminated!");
1187 break;
1188 }
1190 O << MO.getImm();
1191 break;
1192 }
1194 PrintSymbolOperand(MO, O);
1195 break;
1196 }
1198 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
1199 Sym->print(O, MAI);
1200 break;
1201 }
1202 }
1203}
1204
1205bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
1206 raw_ostream &O) {
1207 Register Reg = MO.getReg();
1208 switch (Mode) {
1209 default:
1210 return true; // Unknown mode.
1211 case 'w':
1213 break;
1214 case 'x':
1216 break;
1217 case 't':
1219 break;
1220 }
1221
1223 return false;
1224}
1225
1226// Prints the register in MO using class RC using the offset in the
1227// new register class. This should not be used for cross class
1228// printing.
1229bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
1230 const TargetRegisterClass *RC,
1231 unsigned AltName, raw_ostream &O) {
1232 assert(MO.isReg() && "Should only get here with a register!");
1233 const TargetRegisterInfo *RI = STI->getRegisterInfo();
1234 Register Reg = MO.getReg();
1235 MCRegister RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
1236 if (!RI->regsOverlap(RegToPrint, Reg))
1237 return true;
1238 O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName);
1239 return false;
1240}
1241
1242bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
1243 const char *ExtraCode, raw_ostream &O) {
1244 const MachineOperand &MO = MI->getOperand(OpNum);
1245
1246 // First try the generic code, which knows about modifiers like 'c' and 'n'.
1247 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
1248 return false;
1249
1250 // Does this asm operand have a single letter operand modifier?
1251 if (ExtraCode && ExtraCode[0]) {
1252 if (ExtraCode[1] != 0)
1253 return true; // Unknown modifier.
1254
1255 switch (ExtraCode[0]) {
1256 default:
1257 return true; // Unknown modifier.
1258 case 'w': // Print W register
1259 case 'x': // Print X register
1260 if (MO.isReg())
1261 return printAsmMRegister(MO, ExtraCode[0], O);
1262 if (MO.isImm() && MO.getImm() == 0) {
1263 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
1265 return false;
1266 }
1267 printOperand(MI, OpNum, O);
1268 return false;
1269 case 'b': // Print B register.
1270 case 'h': // Print H register.
1271 case 's': // Print S register.
1272 case 'd': // Print D register.
1273 case 'q': // Print Q register.
1274 case 'z': // Print Z register.
1275 if (MO.isReg()) {
1276 const TargetRegisterClass *RC;
1277 switch (ExtraCode[0]) {
1278 case 'b':
1279 RC = &AArch64::FPR8RegClass;
1280 break;
1281 case 'h':
1282 RC = &AArch64::FPR16RegClass;
1283 break;
1284 case 's':
1285 RC = &AArch64::FPR32RegClass;
1286 break;
1287 case 'd':
1288 RC = &AArch64::FPR64RegClass;
1289 break;
1290 case 'q':
1291 RC = &AArch64::FPR128RegClass;
1292 break;
1293 case 'z':
1294 RC = &AArch64::ZPRRegClass;
1295 break;
1296 default:
1297 return true;
1298 }
1299 return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
1300 }
1301 printOperand(MI, OpNum, O);
1302 return false;
1303 }
1304 }
1305
1306 // According to ARM, we should emit x and v registers unless we have a
1307 // modifier.
1308 if (MO.isReg()) {
1309 Register Reg = MO.getReg();
1310
1311 // If this is a w or x register, print an x register.
1312 if (AArch64::GPR32allRegClass.contains(Reg) ||
1313 AArch64::GPR64allRegClass.contains(Reg))
1314 return printAsmMRegister(MO, 'x', O);
1315
1316 // If this is an x register tuple, print an x register.
1317 if (AArch64::GPR64x8ClassRegClass.contains(Reg))
1318 return printAsmMRegister(MO, 't', O);
1319
1320 unsigned AltName = AArch64::NoRegAltName;
1321 const TargetRegisterClass *RegClass;
1322 if (AArch64::ZPRRegClass.contains(Reg)) {
1323 RegClass = &AArch64::ZPRRegClass;
1324 } else if (AArch64::PPRRegClass.contains(Reg)) {
1325 RegClass = &AArch64::PPRRegClass;
1326 } else if (AArch64::PNRRegClass.contains(Reg)) {
1327 RegClass = &AArch64::PNRRegClass;
1328 } else {
1329 RegClass = &AArch64::FPR128RegClass;
1330 AltName = AArch64::vreg;
1331 }
1332
1333 // If this is a b, h, s, d, or q register, print it as a v register.
1334 return printAsmRegInClass(MO, RegClass, AltName, O);
1335 }
1336
1337 printOperand(MI, OpNum, O);
1338 return false;
1339}
1340
1341bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1342 unsigned OpNum,
1343 const char *ExtraCode,
1344 raw_ostream &O) {
1345 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
1346 return true; // Unknown modifier.
1347
1348 const MachineOperand &MO = MI->getOperand(OpNum);
1349 assert(MO.isReg() && "unexpected inline asm memory operand");
1350 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
1351 return false;
1352}
1353
1354void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
1355 raw_ostream &OS) {
1356 unsigned NOps = MI->getNumOperands();
1357 assert(NOps == 4);
1358 OS << '\t' << MAI.getCommentString() << "DEBUG_VALUE: ";
1359 // cast away const; DIetc do not take const operands for some reason.
1360 OS << MI->getDebugVariable()->getName();
1361 OS << " <- ";
1362 // Frame address. Currently handles register +- offset only.
1363 assert(MI->isIndirectDebugValue());
1364 OS << '[';
1365 for (unsigned I = 0, E = llvm::size(MI->debug_operands()); I < E; ++I) {
1366 if (I != 0)
1367 OS << ", ";
1368 printOperand(MI, I, OS);
1369 }
1370 OS << ']';
1371 OS << "+";
1372 printOperand(MI, NOps - 2, OS);
1373}
1374
1375void AArch64AsmPrinter::emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
1376 ArrayRef<unsigned> JumpTableIndices) {
1377 // Fast return if there is nothing to emit to avoid creating empty sections.
1378 if (JumpTableIndices.empty())
1379 return;
1380 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1381 const auto &F = MF->getFunction();
1383
1384 MCSection *ReadOnlySec = nullptr;
1385 if (TM.Options.EnableStaticDataPartitioning) {
1386 ReadOnlySec =
1387 TLOF.getSectionForJumpTable(F, TM, &JT[JumpTableIndices.front()]);
1388 } else {
1389 ReadOnlySec = TLOF.getSectionForJumpTable(F, TM);
1390 }
1391 OutStreamer->switchSection(ReadOnlySec);
1392
1393 auto AFI = MF->getInfo<AArch64FunctionInfo>();
1394 for (unsigned JTI : JumpTableIndices) {
1395 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
1396
1397 // If this jump table was deleted, ignore it.
1398 if (JTBBs.empty()) continue;
1399
1400 unsigned Size = AFI->getJumpTableEntrySize(JTI);
1401 emitAlignment(Align(Size));
1402 OutStreamer->emitLabel(GetJTISymbol(JTI));
1403
1404 const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1405 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
1406
1407 for (auto *JTBB : JTBBs) {
1408 const MCExpr *Value =
1409 MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext);
1410
1411 // Each entry is:
1412 // .byte/.hword (LBB - Lbase)>>2
1413 // or plain:
1414 // .word LBB - Lbase
1415 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
1416 if (Size != 4)
1418 Value, MCConstantExpr::create(2, OutContext), OutContext);
1419
1420 OutStreamer->emitValue(Value, Size);
1421 }
1422 }
1423}
1424
1425std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
1427AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI,
1428 const MachineInstr *BranchInstr,
1429 const MCSymbol *BranchLabel) const {
1430 const auto AFI = MF->getInfo<AArch64FunctionInfo>();
1431 const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1433 switch (AFI->getJumpTableEntrySize(JTI)) {
1434 case 1:
1435 EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
1436 break;
1437 case 2:
1438 EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
1439 break;
1440 case 4:
1441 EntrySize = codeview::JumpTableEntrySize::Int32;
1442 break;
1443 default:
1444 llvm_unreachable("Unexpected jump table entry size");
1445 }
1446 return std::make_tuple(Base, 0, BranchLabel, EntrySize);
1447}
1448
1449void AArch64AsmPrinter::emitFunctionEntryLabel() {
1450 const Triple &TT = TM.getTargetTriple();
1451 if (TT.isOSBinFormatELF() &&
1452 (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
1453 MF->getFunction().getCallingConv() ==
1454 CallingConv::AArch64_SVE_VectorCall ||
1455 MF->getInfo<AArch64FunctionInfo>()->isSVECC())) {
1456 auto *TS =
1457 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1458 TS->emitDirectiveVariantPCS(CurrentFnSym);
1459 }
1460
1462
1463 if (TT.isWindowsArm64EC() && !MF->getFunction().hasLocalLinkage()) {
1464 // For ARM64EC targets, a function definition's name is mangled differently
1465 // from the normal symbol, emit required aliases here.
1466 auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) {
1467 OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep);
1468 OutStreamer->emitAssignment(
1469 Src, MCSymbolRefExpr::create(Dst, MMI->getContext()));
1470 };
1471
1472 auto getSymbolFromMetadata = [&](StringRef Name) {
1473 MCSymbol *Sym = nullptr;
1474 if (MDNode *Node = MF->getFunction().getMetadata(Name)) {
1475 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1476 Sym = MMI->getContext().getOrCreateSymbol(NameStr);
1477 }
1478 return Sym;
1479 };
1480
1481 SmallVector<MDNode *> UnmangledNames;
1482 MF->getFunction().getMetadata("arm64ec_unmangled_name", UnmangledNames);
1483 for (MDNode *Node : UnmangledNames) {
1484 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1485 MCSymbol *UnmangledSym = MMI->getContext().getOrCreateSymbol(NameStr);
1486 if (std::optional<std::string> MangledName =
1487 getArm64ECMangledFunctionName(UnmangledSym->getName())) {
1488 MCSymbol *ECMangledSym =
1489 MMI->getContext().getOrCreateSymbol(*MangledName);
1490 emitFunctionAlias(UnmangledSym, ECMangledSym);
1491 }
1492 }
1493 if (MCSymbol *ECMangledSym =
1494 getSymbolFromMetadata("arm64ec_ecmangled_name"))
1495 emitFunctionAlias(ECMangledSym, CurrentFnSym);
1496 }
1497}
1498
1499void AArch64AsmPrinter::emitXXStructor(const DataLayout &DL,
1500 const Constant *CV) {
1501 LLVMContext &C = CV->getContext();
1503 "ctors/dtors are to be signed by asm printer");
1504
1505 if (PtrauthInitFini) {
1506 IntegerType *Int32Ty = IntegerType::get(C, 32);
1507 IntegerType *Int64Ty = IntegerType::get(C, 64);
1508 PointerType *PtrTy = PointerType::get(C, 0);
1509
1510 ConstantInt *Key = ConstantInt::get(Int32Ty, AArch64PAuth::InitFiniKey);
1511 ConstantInt *IntDisc = ConstantInt::get(
1514 Constant *AddressDisc = Null;
1515 if (PtrauthInitFiniAddressDisc) {
1517 AddressDisc =
1518 ConstantExpr::getIntToPtr(ConstantInt::get(Int64Ty, Marker), PtrTy);
1519 }
1520
1521 CV = ConstantPtrAuth::get(const_cast<Constant *>(CV), Key, IntDisc,
1522 AddressDisc, /*DeactivationSymbol=*/Null);
1523 }
1524
1525 // Signed pointers will be lowered by AArch64AsmPrinter::lowerConstantPtrAuth.
1527}
1528
1529void AArch64AsmPrinter::emitGlobalAlias(const Module &M,
1530 const GlobalAlias &GA) {
1531 if (auto F = dyn_cast_or_null<Function>(GA.getAliasee())) {
1532 // Global aliases must point to a definition, but unmangled patchable
1533 // symbols are special and need to point to an undefined symbol with "EXP+"
1534 // prefix. Such undefined symbol is resolved by the linker by creating
1535 // x86 thunk that jumps back to the actual EC target.
1536 if (MDNode *Node = F->getMetadata("arm64ec_exp_name")) {
1537 StringRef ExpStr = cast<MDString>(Node->getOperand(0))->getString();
1538 MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr);
1539 MCSymbol *Sym = MMI->getContext().getOrCreateSymbol(GA.getName());
1540
1541 OutStreamer->beginCOFFSymbolDef(ExpSym);
1542 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1543 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1545 OutStreamer->endCOFFSymbolDef();
1546
1547 OutStreamer->beginCOFFSymbolDef(Sym);
1548 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1549 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1551 OutStreamer->endCOFFSymbolDef();
1552 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
1553 OutStreamer->emitAssignment(
1554 Sym, MCSymbolRefExpr::create(ExpSym, MMI->getContext()));
1555 return;
1556 }
1557 }
1559}
1560
1561/// Small jump tables contain an unsigned byte or half, representing the offset
1562/// from the lowest-addressed possible destination to the desired basic
1563/// block. Since all instructions are 4-byte aligned, this is further compressed
1564/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
1565/// materialize the correct destination we need:
1566///
1567/// adr xDest, .LBB0_0
1568/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
1569/// add xDest, xDest, xScratch (with "lsl #2" for smaller entries)
1570void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer,
1571 const llvm::MachineInstr &MI) {
1572 Register DestReg = MI.getOperand(0).getReg();
1573 Register ScratchReg = MI.getOperand(1).getReg();
1574 Register ScratchRegW =
1575 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
1576 Register TableReg = MI.getOperand(2).getReg();
1577 Register EntryReg = MI.getOperand(3).getReg();
1578 int JTIdx = MI.getOperand(4).getIndex();
1579 int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
1580
1581 // This has to be first because the compression pass based its reachability
1582 // calculations on the start of the JumpTableDest instruction.
1583 auto Label =
1584 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
1585
1586 // If we don't already have a symbol to use as the base, use the ADR
1587 // instruction itself.
1588 if (!Label) {
1590 AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label);
1591 OutStreamer.emitLabel(Label);
1592 }
1593
1594 auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext());
1595 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
1596 .addReg(DestReg)
1597 .addExpr(LabelExpr));
1598
1599 // Load the number of instruction-steps to offset from the label.
1600 unsigned LdrOpcode;
1601 switch (Size) {
1602 case 1: LdrOpcode = AArch64::LDRBBroX; break;
1603 case 2: LdrOpcode = AArch64::LDRHHroX; break;
1604 case 4: LdrOpcode = AArch64::LDRSWroX; break;
1605 default:
1606 llvm_unreachable("Unknown jump table size");
1607 }
1608
1609 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
1610 .addReg(Size == 4 ? ScratchReg : ScratchRegW)
1611 .addReg(TableReg)
1612 .addReg(EntryReg)
1613 .addImm(0)
1614 .addImm(Size == 1 ? 0 : 1));
1615
1616 // Add to the already materialized base label address, multiplying by 4 if
1617 // compressed.
1618 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1619 .addReg(DestReg)
1620 .addReg(DestReg)
1621 .addReg(ScratchReg)
1622 .addImm(Size == 4 ? 0 : 2));
1623}
1624
1625void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) {
1626 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
1627 assert(MJTI && "Can't lower jump-table dispatch without JTI");
1628
1629 const std::vector<MachineJumpTableEntry> &JTs = MJTI->getJumpTables();
1630 assert(!JTs.empty() && "Invalid JT index for jump-table dispatch");
1631
1632 // Emit:
1633 // mov x17, #<size of table> ; depending on table size, with MOVKs
1634 // cmp x16, x17 ; or #imm if table size fits in 12-bit
1635 // csel x16, x16, xzr, ls ; check for index overflow
1636 //
1637 // adrp x17, Ltable@PAGE ; materialize table address
1638 // add x17, Ltable@PAGEOFF
1639 // ldrsw x16, [x17, x16, lsl #2] ; load table entry
1640 //
1641 // Lanchor:
1642 // adr x17, Lanchor ; compute target address
1643 // add x16, x17, x16
1644 // br x16 ; branch to target
1645
1646 MachineOperand JTOp = MI.getOperand(0);
1647
1648 unsigned JTI = JTOp.getIndex();
1649 assert(!AArch64FI->getJumpTableEntryPCRelSymbol(JTI) &&
1650 "unsupported compressed jump table");
1651
1652 const uint64_t NumTableEntries = JTs[JTI].MBBs.size();
1653
1654 // cmp only supports a 12-bit immediate. If we need more, materialize the
1655 // immediate, using x17 as a scratch register.
1656 uint64_t MaxTableEntry = NumTableEntries - 1;
1657 if (isUInt<12>(MaxTableEntry)) {
1658 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXri)
1659 .addReg(AArch64::XZR)
1660 .addReg(AArch64::X16)
1661 .addImm(MaxTableEntry)
1662 .addImm(0));
1663 } else {
1664 emitMOVZ(AArch64::X17, static_cast<uint16_t>(MaxTableEntry), 0);
1665 // It's sad that we have to manually materialize instructions, but we can't
1666 // trivially reuse the main pseudo expansion logic.
1667 // A MOVK sequence is easy enough to generate and handles the general case.
1668 for (int Offset = 16; Offset < 64; Offset += 16) {
1669 if ((MaxTableEntry >> Offset) == 0)
1670 break;
1671 emitMOVK(AArch64::X17, static_cast<uint16_t>(MaxTableEntry >> Offset),
1672 Offset);
1673 }
1674 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs)
1675 .addReg(AArch64::XZR)
1676 .addReg(AArch64::X16)
1677 .addReg(AArch64::X17)
1678 .addImm(0));
1679 }
1680
1681 // This picks entry #0 on failure.
1682 // We might want to trap instead.
1683 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CSELXr)
1684 .addReg(AArch64::X16)
1685 .addReg(AArch64::X16)
1686 .addReg(AArch64::XZR)
1687 .addImm(AArch64CC::LS));
1688
1689 // Prepare the @PAGE/@PAGEOFF low/high operands.
1690 MachineOperand JTMOHi(JTOp), JTMOLo(JTOp);
1691 MCOperand JTMCHi, JTMCLo;
1692
1693 JTMOHi.setTargetFlags(AArch64II::MO_PAGE);
1694 JTMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
1695
1696 MCInstLowering.lowerOperand(JTMOHi, JTMCHi);
1697 MCInstLowering.lowerOperand(JTMOLo, JTMCLo);
1698
1699 EmitToStreamer(
1700 *OutStreamer,
1701 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(JTMCHi));
1702
1703 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri)
1704 .addReg(AArch64::X17)
1705 .addReg(AArch64::X17)
1706 .addOperand(JTMCLo)
1707 .addImm(0));
1708
1709 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX)
1710 .addReg(AArch64::X16)
1711 .addReg(AArch64::X17)
1712 .addReg(AArch64::X16)
1713 .addImm(0)
1714 .addImm(1));
1715
1716 MCSymbol *AdrLabel = MF->getContext().createTempSymbol();
1717 const auto *AdrLabelE = MCSymbolRefExpr::create(AdrLabel, MF->getContext());
1718 AArch64FI->setJumpTableEntryInfo(JTI, 4, AdrLabel);
1719
1720 OutStreamer->emitLabel(AdrLabel);
1721 EmitToStreamer(
1722 *OutStreamer,
1723 MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addExpr(AdrLabelE));
1724
1725 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1726 .addReg(AArch64::X16)
1727 .addReg(AArch64::X17)
1728 .addReg(AArch64::X16)
1729 .addImm(0));
1730
1731 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
1732}
1733
1734void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer,
1735 const llvm::MachineInstr &MI) {
1736 unsigned Opcode = MI.getOpcode();
1737 assert(STI->hasMOPS());
1738 assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
1739
1740 const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
1741 if (Opcode == AArch64::MOPSMemoryCopyPseudo)
1742 return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
1743 if (Opcode == AArch64::MOPSMemoryMovePseudo)
1744 return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
1745 if (Opcode == AArch64::MOPSMemorySetPseudo)
1746 return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
1747 if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
1748 return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
1749 llvm_unreachable("Unhandled memory operation pseudo");
1750 }();
1751 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
1752 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
1753
1754 for (auto Op : Ops) {
1755 int i = 0;
1756 auto MCIB = MCInstBuilder(Op);
1757 // Destination registers
1758 MCIB.addReg(MI.getOperand(i++).getReg());
1759 MCIB.addReg(MI.getOperand(i++).getReg());
1760 if (!IsSet)
1761 MCIB.addReg(MI.getOperand(i++).getReg());
1762 // Input registers
1763 MCIB.addReg(MI.getOperand(i++).getReg());
1764 MCIB.addReg(MI.getOperand(i++).getReg());
1765 MCIB.addReg(MI.getOperand(i++).getReg());
1766
1767 EmitToStreamer(OutStreamer, MCIB);
1768 }
1769}
1770
1771void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1772 const MachineInstr &MI) {
1773 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
1774
1775 auto &Ctx = OutStreamer.getContext();
1776 MCSymbol *MILabel = Ctx.createTempSymbol();
1777 OutStreamer.emitLabel(MILabel);
1778
1779 SM.recordStackMap(*MILabel, MI);
1780 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1781
1782 // Scan ahead to trim the shadow.
1783 const MachineBasicBlock &MBB = *MI.getParent();
1785 ++MII;
1786 while (NumNOPBytes > 0) {
1787 if (MII == MBB.end() || MII->isCall() ||
1788 MII->getOpcode() == AArch64::DBG_VALUE ||
1789 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1790 MII->getOpcode() == TargetOpcode::STACKMAP)
1791 break;
1792 ++MII;
1793 NumNOPBytes -= 4;
1794 }
1795
1796 // Emit nops.
1797 for (unsigned i = 0; i < NumNOPBytes; i += 4)
1798 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::NOP));
1799}
1800
1801// Lower a patchpoint of the form:
1802// [<def>], <id>, <numBytes>, <target>, <numArgs>
1803void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1804 const MachineInstr &MI) {
1805 auto &Ctx = OutStreamer.getContext();
1806 MCSymbol *MILabel = Ctx.createTempSymbol();
1807 OutStreamer.emitLabel(MILabel);
1808 SM.recordPatchPoint(*MILabel, MI);
1809
1810 PatchPointOpers Opers(&MI);
1811
1812 int64_t CallTarget = Opers.getCallTarget().getImm();
1813 unsigned EncodedBytes = 0;
1814 if (CallTarget) {
1815 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
1816 "High 16 bits of call target should be zero.");
1817 Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
1818 EncodedBytes = 16;
1819 // Materialize the jump address:
1820 emitMOVZ(ScratchReg, (CallTarget >> 32) & 0xFFFF, 32);
1821 emitMOVK(ScratchReg, (CallTarget >> 16) & 0xFFFF, 16);
1822 emitMOVK(ScratchReg, CallTarget & 0xFFFF, 0);
1823 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
1824 }
1825 // Emit padding.
1826 unsigned NumBytes = Opers.getNumPatchBytes();
1827 assert(NumBytes >= EncodedBytes &&
1828 "Patchpoint can't request size less than the length of a call.");
1829 assert((NumBytes - EncodedBytes) % 4 == 0 &&
1830 "Invalid number of NOP bytes requested!");
1831 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
1832 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::NOP));
1833}
1834
1835void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1836 const MachineInstr &MI) {
1837 StatepointOpers SOpers(&MI);
1838 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1839 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1840 for (unsigned i = 0; i < PatchBytes; i += 4)
1841 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::NOP));
1842 } else {
1843 // Lower call target and choose correct opcode
1844 const MachineOperand &CallTarget = SOpers.getCallTarget();
1845 MCOperand CallTargetMCOp;
1846 unsigned CallOpcode;
1847 switch (CallTarget.getType()) {
1850 MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1851 CallOpcode = AArch64::BL;
1852 break;
1854 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
1855 CallOpcode = AArch64::BL;
1856 break;
1858 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
1859 CallOpcode = AArch64::BLR;
1860 break;
1861 default:
1862 llvm_unreachable("Unsupported operand type in statepoint call target");
1863 break;
1864 }
1865
1866 EmitToStreamer(OutStreamer,
1867 MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
1868 }
1869
1870 auto &Ctx = OutStreamer.getContext();
1871 MCSymbol *MILabel = Ctx.createTempSymbol();
1872 OutStreamer.emitLabel(MILabel);
1873 SM.recordStatepoint(*MILabel, MI);
1874}
1875
1876void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) {
1877 // FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>,
1878 // <opcode>, <operands>
1879
1880 Register DefRegister = FaultingMI.getOperand(0).getReg();
1882 static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm());
1883 MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol();
1884 unsigned Opcode = FaultingMI.getOperand(3).getImm();
1885 unsigned OperandsBeginIdx = 4;
1886
1887 auto &Ctx = OutStreamer->getContext();
1888 MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1889 OutStreamer->emitLabel(FaultingLabel);
1890
1891 assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!");
1892 FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1893
1894 MCInst MI;
1895 MI.setOpcode(Opcode);
1896
1897 if (DefRegister != (Register)0)
1898 MI.addOperand(MCOperand::createReg(DefRegister));
1899
1900 for (const MachineOperand &MO :
1901 llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) {
1902 MCOperand Dest;
1903 lowerOperand(MO, Dest);
1904 MI.addOperand(Dest);
1905 }
1906
1907 OutStreamer->AddComment("on-fault: " + HandlerLabel->getName());
1908 EmitToStreamer(MI);
1909}
1910
1911void AArch64AsmPrinter::emitMovXReg(Register Dest, Register Src) {
1912 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1913 .addReg(Dest)
1914 .addReg(AArch64::XZR)
1915 .addReg(Src)
1916 .addImm(0));
1917}
1918
1919void AArch64AsmPrinter::emitMOVZ(Register Dest, uint64_t Imm, unsigned Shift) {
1920 bool Is64Bit = AArch64::GPR64RegClass.contains(Dest);
1921 EmitToStreamer(*OutStreamer,
1922 MCInstBuilder(Is64Bit ? AArch64::MOVZXi : AArch64::MOVZWi)
1923 .addReg(Dest)
1924 .addImm(Imm)
1925 .addImm(Shift));
1926}
1927
1928void AArch64AsmPrinter::emitMOVK(Register Dest, uint64_t Imm, unsigned Shift) {
1929 bool Is64Bit = AArch64::GPR64RegClass.contains(Dest);
1930 EmitToStreamer(*OutStreamer,
1931 MCInstBuilder(Is64Bit ? AArch64::MOVKXi : AArch64::MOVKWi)
1932 .addReg(Dest)
1933 .addReg(Dest)
1934 .addImm(Imm)
1935 .addImm(Shift));
1936}
1937
1938void AArch64AsmPrinter::emitAUT(AArch64PACKey::ID Key, Register Pointer,
1939 Register Disc) {
1940 bool IsZeroDisc = Disc == AArch64::XZR;
1941 unsigned Opcode = getAUTOpcodeForKey(Key, IsZeroDisc);
1942
1943 // autiza x16 ; if IsZeroDisc
1944 // autia x16, x17 ; if !IsZeroDisc
1945 MCInst AUTInst;
1946 AUTInst.setOpcode(Opcode);
1947 AUTInst.addOperand(MCOperand::createReg(Pointer));
1948 AUTInst.addOperand(MCOperand::createReg(Pointer));
1949 if (!IsZeroDisc)
1950 AUTInst.addOperand(MCOperand::createReg(Disc));
1951
1952 EmitToStreamer(AUTInst);
1953}
1954
1955void AArch64AsmPrinter::emitPAC(AArch64PACKey::ID Key, Register Pointer,
1956 Register Disc) {
1957 bool IsZeroDisc = Disc == AArch64::XZR;
1958 unsigned Opcode = getPACOpcodeForKey(Key, IsZeroDisc);
1959
1960 // paciza x16 ; if IsZeroDisc
1961 // pacia x16, x17 ; if !IsZeroDisc
1962 MCInst PACInst;
1963 PACInst.setOpcode(Opcode);
1964 PACInst.addOperand(MCOperand::createReg(Pointer));
1965 PACInst.addOperand(MCOperand::createReg(Pointer));
1966 if (!IsZeroDisc)
1967 PACInst.addOperand(MCOperand::createReg(Disc));
1968
1969 EmitToStreamer(PACInst);
1970}
1971
1972void AArch64AsmPrinter::emitBLRA(bool IsCall, AArch64PACKey::ID Key,
1973 Register Target, Register Disc) {
1974 bool IsZeroDisc = Disc == AArch64::XZR;
1975 unsigned Opcode = getBranchOpcodeForKey(IsCall, Key, IsZeroDisc);
1976
1977 // blraaz x16 ; if IsZeroDisc
1978 // blraa x16, x17 ; if !IsZeroDisc
1979 MCInst Inst;
1980 Inst.setOpcode(Opcode);
1981 Inst.addOperand(MCOperand::createReg(Target));
1982 if (!IsZeroDisc)
1983 Inst.addOperand(MCOperand::createReg(Disc));
1984 EmitToStreamer(Inst);
1985}
1986
1987void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
1988 Register DestReg = MI.getOperand(0).getReg();
1989 if (!STI->hasZeroCycleZeroingFPWorkaround() && STI->isNeonAvailable()) {
1990 if (STI->hasZeroCycleZeroingFPR64()) {
1991 // Convert H/S register to corresponding D register
1992 const AArch64RegisterInfo *TRI = STI->getRegisterInfo();
1993 if (AArch64::FPR16RegClass.contains(DestReg))
1994 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::hsub,
1995 &AArch64::FPR64RegClass);
1996 else if (AArch64::FPR32RegClass.contains(DestReg))
1997 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::ssub,
1998 &AArch64::FPR64RegClass);
1999 else
2000 assert(AArch64::FPR64RegClass.contains(DestReg));
2001
2002 MCInst MOVI;
2003 MOVI.setOpcode(AArch64::MOVID);
2004 MOVI.addOperand(MCOperand::createReg(DestReg));
2006 EmitToStreamer(*OutStreamer, MOVI);
2007 ++NumZCZeroingInstrsFPR;
2008 } else if (STI->hasZeroCycleZeroingFPR128()) {
2009 // Convert H/S/D register to corresponding Q register
2010 const AArch64RegisterInfo *TRI = STI->getRegisterInfo();
2011 if (AArch64::FPR16RegClass.contains(DestReg)) {
2012 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::hsub,
2013 &AArch64::FPR128RegClass);
2014 } else if (AArch64::FPR32RegClass.contains(DestReg)) {
2015 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::ssub,
2016 &AArch64::FPR128RegClass);
2017 } else {
2018 assert(AArch64::FPR64RegClass.contains(DestReg));
2019 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::dsub,
2020 &AArch64::FPR128RegClass);
2021 }
2022
2023 MCInst MOVI;
2024 MOVI.setOpcode(AArch64::MOVIv2d_ns);
2025 MOVI.addOperand(MCOperand::createReg(DestReg));
2027 EmitToStreamer(*OutStreamer, MOVI);
2028 ++NumZCZeroingInstrsFPR;
2029 } else {
2030 emitFMov0AsFMov(MI, DestReg);
2031 }
2032 } else {
2033 emitFMov0AsFMov(MI, DestReg);
2034 }
2035}
2036
2037void AArch64AsmPrinter::emitFMov0AsFMov(const MachineInstr &MI,
2038 Register DestReg) {
2039 MCInst FMov;
2040 switch (MI.getOpcode()) {
2041 default:
2042 llvm_unreachable("Unexpected opcode");
2043 case AArch64::FMOVH0:
2044 FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
2045 if (!STI->hasFullFP16())
2046 DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
2047 FMov.addOperand(MCOperand::createReg(DestReg));
2048 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
2049 break;
2050 case AArch64::FMOVS0:
2051 FMov.setOpcode(AArch64::FMOVWSr);
2052 FMov.addOperand(MCOperand::createReg(DestReg));
2053 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
2054 break;
2055 case AArch64::FMOVD0:
2056 FMov.setOpcode(AArch64::FMOVXDr);
2057 FMov.addOperand(MCOperand::createReg(DestReg));
2058 FMov.addOperand(MCOperand::createReg(AArch64::XZR));
2059 break;
2060 }
2061 EmitToStreamer(*OutStreamer, FMov);
2062}
2063
2064Register AArch64AsmPrinter::emitPtrauthDiscriminator(uint64_t Disc,
2065 Register AddrDisc,
2066 Register ScratchReg,
2067 bool MayClobberAddrDisc) {
2068 assert(isPtrauthRegSafe(ScratchReg) &&
2069 "Safe scratch register must be provided by the caller");
2070 assert(isUInt<16>(Disc) && "Constant discriminator is too wide");
2071
2072 // So far we've used NoRegister in pseudos. Now we need real encodings.
2073 if (!AddrDisc.isValid())
2074 AddrDisc = AArch64::XZR;
2075
2076 // If there is no constant discriminator, there's no blend involved:
2077 // just use the address discriminator register as-is (XZR or not).
2078 if (!Disc)
2079 return AddrDisc;
2080
2081 // If there's only a constant discriminator, MOV it into the scratch register.
2082 if (AddrDisc == AArch64::XZR) {
2083 emitMOVZ(ScratchReg, Disc, 0);
2084 return ScratchReg;
2085 }
2086
2087 // If there are both, emit a blend into the scratch register.
2088
2089 // Check if we can save one MOV instruction.
2090 if (MayClobberAddrDisc && isPtrauthRegSafe(AddrDisc)) {
2091 ScratchReg = AddrDisc;
2092 } else {
2093 emitMovXReg(ScratchReg, AddrDisc);
2094 assert(ScratchReg != AddrDisc &&
2095 "Forbidden to clobber AddrDisc, but have to");
2096 }
2097
2098 emitMOVK(ScratchReg, Disc, 48);
2099 return ScratchReg;
2100}
2101
2102/// Emit a code sequence to check an authenticated pointer value.
2103///
2104/// This function emits a sequence of instructions that checks if TestedReg was
2105/// authenticated successfully. On success, execution continues at the next
2106/// instruction after the sequence.
2107///
2108/// The action performed on failure depends on the OnFailure argument:
2109/// * if OnFailure is not nullptr, control is transferred to that label after
2110/// clearing the PAC field
2111/// * otherwise, BRK instruction is emitted to generate an error
2112void AArch64AsmPrinter::emitPtrauthCheckAuthenticatedValue(
2113 Register TestedReg, Register ScratchReg, AArch64PACKey::ID Key,
2114 AArch64PAuth::AuthCheckMethod Method, const MCSymbol *OnFailure) {
2115 // Insert a sequence to check if authentication of TestedReg succeeded,
2116 // such as:
2117 //
2118 // - checked and clearing:
2119 // ; x16 is TestedReg, x17 is ScratchReg
2120 // mov x17, x16
2121 // xpaci x17
2122 // cmp x16, x17
2123 // b.eq Lsuccess
2124 // mov x16, x17
2125 // b Lend
2126 // Lsuccess:
2127 // ; skipped if authentication failed
2128 // Lend:
2129 // ...
2130 //
2131 // - checked and trapping:
2132 // mov x17, x16
2133 // xpaci x17
2134 // cmp x16, x17
2135 // b.eq Lsuccess
2136 // brk #<0xc470 + aut key>
2137 // Lsuccess:
2138 // ...
2139 //
2140 // See the documentation on AuthCheckMethod enumeration constants for
2141 // the specific code sequences that can be used to perform the check.
2143
2144 if (Method == AuthCheckMethod::None)
2145 return;
2146 if (Method == AuthCheckMethod::DummyLoad) {
2147 EmitToStreamer(MCInstBuilder(AArch64::LDRWui)
2148 .addReg(getWRegFromXReg(ScratchReg))
2149 .addReg(TestedReg)
2150 .addImm(0));
2151 assert(!OnFailure && "DummyLoad always traps on error");
2152 return;
2153 }
2154
2155 MCSymbol *SuccessSym = createTempSymbol("auth_success_");
2156 if (Method == AuthCheckMethod::XPAC || Method == AuthCheckMethod::XPACHint) {
2157 // mov Xscratch, Xtested
2158 emitMovXReg(ScratchReg, TestedReg);
2159
2160 if (Method == AuthCheckMethod::XPAC) {
2161 // xpac(i|d) Xscratch
2162 unsigned XPACOpc = getXPACOpcodeForKey(Key);
2163 EmitToStreamer(
2164 MCInstBuilder(XPACOpc).addReg(ScratchReg).addReg(ScratchReg));
2165 } else {
2166 // xpaclri
2167
2168 // Note that this method applies XPAC to TestedReg instead of ScratchReg.
2169 assert(TestedReg == AArch64::LR &&
2170 "XPACHint mode is only compatible with checking the LR register");
2172 "XPACHint mode is only compatible with I-keys");
2173 EmitToStreamer(MCInstBuilder(AArch64::XPACLRI));
2174 }
2175
2176 // cmp Xtested, Xscratch
2177 EmitToStreamer(MCInstBuilder(AArch64::SUBSXrs)
2178 .addReg(AArch64::XZR)
2179 .addReg(TestedReg)
2180 .addReg(ScratchReg)
2181 .addImm(0));
2182
2183 // b.eq Lsuccess
2184 EmitToStreamer(
2185 MCInstBuilder(AArch64::Bcc)
2186 .addImm(AArch64CC::EQ)
2187 .addExpr(MCSymbolRefExpr::create(SuccessSym, OutContext)));
2188 } else if (Method == AuthCheckMethod::HighBitsNoTBI) {
2189 // eor Xscratch, Xtested, Xtested, lsl #1
2190 EmitToStreamer(MCInstBuilder(AArch64::EORXrs)
2191 .addReg(ScratchReg)
2192 .addReg(TestedReg)
2193 .addReg(TestedReg)
2194 .addImm(1));
2195 // tbz Xscratch, #62, Lsuccess
2196 EmitToStreamer(
2197 MCInstBuilder(AArch64::TBZX)
2198 .addReg(ScratchReg)
2199 .addImm(62)
2200 .addExpr(MCSymbolRefExpr::create(SuccessSym, OutContext)));
2201 } else {
2202 llvm_unreachable("Unsupported check method");
2203 }
2204
2205 if (!OnFailure) {
2206 // Trapping sequences do a 'brk'.
2207 // brk #<0xc470 + aut key>
2208 EmitToStreamer(MCInstBuilder(AArch64::BRK).addImm(0xc470 | Key));
2209 } else {
2210 // Non-trapping checked sequences return the stripped result in TestedReg,
2211 // skipping over success-only code (such as re-signing the pointer) by
2212 // jumping to OnFailure label.
2213 // Note that this can introduce an authentication oracle (such as based on
2214 // the high bits of the re-signed value).
2215
2216 // FIXME: The XPAC method can be optimized by applying XPAC to TestedReg
2217 // instead of ScratchReg, thus eliminating one `mov` instruction.
2218 // Both XPAC and XPACHint can be further optimized by not using a
2219 // conditional branch jumping over an unconditional one.
2220
2221 switch (Method) {
2222 case AuthCheckMethod::XPACHint:
2223 // LR is already XPAC-ed at this point.
2224 break;
2225 case AuthCheckMethod::XPAC:
2226 // mov Xtested, Xscratch
2227 emitMovXReg(TestedReg, ScratchReg);
2228 break;
2229 default:
2230 // If Xtested was not XPAC-ed so far, emit XPAC here.
2231 // xpac(i|d) Xtested
2232 unsigned XPACOpc = getXPACOpcodeForKey(Key);
2233 EmitToStreamer(
2234 MCInstBuilder(XPACOpc).addReg(TestedReg).addReg(TestedReg));
2235 }
2236
2237 // b Lend
2238 const auto *OnFailureExpr = MCSymbolRefExpr::create(OnFailure, OutContext);
2239 EmitToStreamer(MCInstBuilder(AArch64::B).addExpr(OnFailureExpr));
2240 }
2241
2242 // If the auth check succeeds, we can continue.
2243 // Lsuccess:
2244 OutStreamer->emitLabel(SuccessSym);
2245}
2246
2247// With Pointer Authentication, it may be needed to explicitly check the
2248// authenticated value in LR before performing a tail call.
2249// Otherwise, the callee may re-sign the invalid return address,
2250// introducing a signing oracle.
2251void AArch64AsmPrinter::emitPtrauthTailCallHardening(const MachineInstr *TC) {
2252 if (!AArch64FI->shouldSignReturnAddress(*MF))
2253 return;
2254
2255 auto LRCheckMethod = STI->getAuthenticatedLRCheckMethod(*MF);
2256 if (LRCheckMethod == AArch64PAuth::AuthCheckMethod::None)
2257 return;
2258
2259 const AArch64RegisterInfo *TRI = STI->getRegisterInfo();
2260 Register ScratchReg =
2261 TC->readsRegister(AArch64::X16, TRI) ? AArch64::X17 : AArch64::X16;
2262 assert(!TC->readsRegister(ScratchReg, TRI) &&
2263 "Neither x16 nor x17 is available as a scratch register");
2266 emitPtrauthCheckAuthenticatedValue(AArch64::LR, ScratchReg, Key,
2267 LRCheckMethod);
2268}
2269
2270bool AArch64AsmPrinter::emitDeactivationSymbolRelocation(Value *DS) {
2271 if (!DS)
2272 return false;
2273
2274 if (isa<GlobalAlias>(DS)) {
2275 // Just emit the nop directly.
2276 EmitToStreamer(MCInstBuilder(AArch64::NOP));
2277 return true;
2278 }
2279 MCSymbol *Dot = OutContext.createTempSymbol();
2280 OutStreamer->emitLabel(Dot);
2281 const MCExpr *DeactDotExpr = MCSymbolRefExpr::create(Dot, OutContext);
2282
2283 const MCExpr *DSExpr = MCSymbolRefExpr::create(
2284 OutContext.getOrCreateSymbol(DS->getName()), OutContext);
2285 OutStreamer->emitRelocDirective(*DeactDotExpr, "R_AARCH64_PATCHINST", DSExpr,
2286 SMLoc());
2287 return false;
2288}
2289
2290AArch64AsmPrinter::PtrAuthSchema AArch64AsmPrinter::PtrAuthSchema::CreateImmReg(
2291 AArch64PACKey::ID Key, uint64_t IntDisc, const MachineOperand &AddrDiscOp) {
2292 PtrAuthSchema Schema;
2293 Schema.Key = Key;
2294 Schema.IntDisc = IntDisc;
2295 Schema.AddrDisc = AddrDiscOp.getReg();
2296 Schema.AddrDiscIsKilled = AddrDiscOp.isKill();
2297 Schema.PCDisc = Register();
2298 return Schema;
2299}
2300
2301AArch64AsmPrinter::PtrAuthSchema AArch64AsmPrinter::PtrAuthSchema::CreateRegReg(
2302 AArch64PACKey::ID Key, Register AddrDisc, Register PCDisc) {
2303 assert(PCDisc.isValid() && "Use CreateImmReg for non-PC schemas");
2304 PtrAuthSchema Schema;
2305 Schema.Key = Key;
2306 Schema.IntDisc = 0;
2307 Schema.AddrDisc = AddrDisc;
2308 Schema.AddrDiscIsKilled = false;
2309 Schema.PCDisc = PCDisc;
2310 return Schema;
2311}
2312
2313void AArch64AsmPrinter::emitPtrauthApplyIndirectAddend(Register Pointer,
2314 Register Scratch,
2315 int64_t Addend) {
2316 if (isInt<9>(Addend)) {
2317 // ldrsw Scratch, [Pointer, #Addend]! ; note: Pointer+Addend is used later.
2318 EmitToStreamer(MCInstBuilder(AArch64::LDRSWpre)
2319 .addReg(Pointer)
2320 .addReg(Scratch)
2321 .addReg(Pointer)
2322 .addImm(/*simm9:*/ Addend));
2323 } else {
2324 // Pointer += Addend computation has 2 variants
2325 if (isUInt<24>(Addend)) {
2326 // Variant 1: add Pointer, Pointer, (Addend >> shift12) lsl shift12
2327 // This can take up to 2 instructions.
2328 for (int BitPos = 0; BitPos != 24 && (Addend >> BitPos); BitPos += 12) {
2329 EmitToStreamer(
2330 MCInstBuilder(AArch64::ADDXri)
2331 .addReg(Pointer)
2332 .addReg(Pointer)
2333 .addImm((Addend >> BitPos) & 0xfff)
2334 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
2335 }
2336 } else {
2337 // Variant 2: accumulate constant in Scratch 16 bits at a time,
2338 // and add it to Pointer. This can take 2-5 instructions.
2339 emitMOVZ(Scratch, Addend & 0xffff, 0);
2340 for (int Offset = 16; Offset < 64; Offset += 16) {
2341 if (unsigned Fragment = (Addend >> Offset) & 0xffff)
2342 emitMOVK(Scratch, Fragment, Offset);
2343 }
2344
2345 // add Pointer, Pointer, Scratch
2346 EmitToStreamer(MCInstBuilder(AArch64::ADDXrs)
2347 .addReg(Pointer)
2348 .addReg(Pointer)
2349 .addReg(Scratch)
2350 .addImm(0));
2351 }
2352 // ldrsw Scratch, [Pointer]
2353 EmitToStreamer(MCInstBuilder(AArch64::LDRSWui)
2354 .addReg(Scratch)
2355 .addReg(Pointer)
2356 .addImm(0));
2357 }
2358 // add Pointer, Pointer, Scratch
2359 EmitToStreamer(MCInstBuilder(AArch64::ADDXrs)
2360 .addReg(Pointer)
2361 .addReg(Pointer)
2362 .addReg(Scratch)
2363 .addImm(0));
2364}
2365
2366static PtrauthCheckMode getCheckMode(const MachineFunction *MF) {
2368
2369 // If an override is passed via command line argument, just use that value.
2370 if (std::optional<PtrauthCheckMode> Mode =
2371 STI.getCLOpts().ptrauth_auth_checks)
2372 return *Mode;
2373
2374 // Otherwise, on an FPAC CPU, you get traps whether you want them or not:
2375 // there's no point in emitting checks or traps.
2376 if (STI.hasFPAC())
2377 return PtrauthCheckMode::Unchecked;
2378
2379 bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps");
2380 return ShouldTrap ? PtrauthCheckMode::Trap : PtrauthCheckMode::Poison;
2381}
2382
2383// We expand non-signing AUT* pseudo instructions into a sequence of the form
2384//
2385// ; 1. Authenticate Pointer
2386//
2387// or
2388//
2389// ; 1. Authenticate Pointer
2390// ; 2. Check that Pointer is valid, trap otherwise
2391//
2392// We expand AUT*PAC pseudo instructions into a sequence of the form
2393// (with addend only applied if Addend argument is given):
2394//
2395// ; 1. Authenticate Pointer
2396// ; 3. Apply addend and sign Pointer
2397//
2398// or
2399//
2400// ; 1. Authenticate Pointer
2401// ; 2. Check that Pointer is valid, trap otherwise
2402// ; 3. Apply addend and sign Pointer
2403//
2404// or
2405//
2406// ; 1. Authenticate Pointer
2407// ; 2. Check that Pointer is valid, jump to .Lon_failure otherwise
2408// ; 3. Apply addend and sign Pointer
2409// .Lon_failure:
2410//
2411void AArch64AsmPrinter::emitPtrauthAuthResign(
2412 Register Pointer, Register Scratch, PtrAuthSchema AuthSchema,
2413 std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend,
2414 Value *DS) {
2415 const PtrauthCheckMode CheckMode = getCheckMode(MF);
2416 const bool IsAuthWithPC = AuthSchema.PCDisc.isValid();
2417 assert(!SignSchema || !SignSchema->PCDisc.isValid());
2418
2419 Register SignAddrDiscOrNone = SignSchema ? SignSchema->AddrDisc : Register();
2420
2421 // 1. Authenticate Pointer - this is the only common step.
2422 // It is more complex than signing because AUTI[AB]171615 may be used.
2423
2424 if (IsAuthWithPC) {
2425 assert(Pointer == AArch64::X17 && Scratch == AArch64::X16 &&
2426 "AUTPCPAC must use x17/x16 as Pointer/Scratch");
2427
2428 assert(AuthSchema.AddrDisc == AArch64::X16 &&
2429 "AUTPCPAC requires address discriminator in X16");
2430
2431 assert(AuthSchema.PCDisc == AArch64::X15 &&
2432 "AUTPCPAC requires PC discriminator in X15");
2433
2434 assert(AuthSchema.IntDisc == 0 && "AUTPCPAC does not support IntDisc");
2435
2436 assert((AuthSchema.Key == AArch64PACKey::IB ||
2437 AuthSchema.Key == AArch64PACKey::IA) &&
2438 "AUTPCPAC only supports AUT-ing with IA/IB");
2439
2440 if (!emitDeactivationSymbolRelocation(DS)) {
2441 unsigned AutOpc = (AuthSchema.Key == AArch64PACKey::IB)
2442 ? AArch64::AUTIB171615
2443 : AArch64::AUTIA171615;
2444 EmitToStreamer(MCInstBuilder(AutOpc));
2445 }
2446 } else {
2447 // emitPtrauthDiscriminator is allowed to clobber AuthSchema.AddrDisc as
2448 // long as it is not used past this point neither externally (the register
2449 // operand is "killed"), nor internally (it does not alias anything being
2450 // used later by this pseudo instruction).
2451 //
2452 // Note that, while rather unlikely, it is technically possible to use the
2453 // Pointer to compute its own discriminator.
2454 Register AUTDiscReg = emitPtrauthDiscriminator(
2455 AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch,
2456 AuthSchema.addrDiscIsKilledAndNoneOf({Pointer, SignAddrDiscOrNone}));
2457 if (!emitDeactivationSymbolRelocation(DS))
2458 emitAUT(AuthSchema.Key, Pointer, AUTDiscReg);
2459 }
2460
2461 // The other two steps are optional, define lambdas for them:
2462 // 2. Check that Pointer is valid, on failure jump to label or trap.
2463 auto EmitCheck = [&](MCSymbol *OnFailure = nullptr) {
2464 emitPtrauthCheckAuthenticatedValue(Pointer, Scratch, AuthSchema.Key,
2465 AArch64PAuth::AuthCheckMethod::XPAC,
2466 OnFailure);
2467 };
2468 // 3. Apply addend and sign Pointer.
2469 auto EmitResignOnSuccess = [&]() {
2470 if (Addend.has_value())
2471 emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend);
2472
2473 assert(Pointer != SignSchema->AddrDisc && "Pointer is early-clobbered");
2474 Register PACDiscReg =
2475 emitPtrauthDiscriminator(SignSchema->IntDisc, SignSchema->AddrDisc,
2476 Scratch, SignSchema->AddrDiscIsKilled);
2477 emitPAC(SignSchema->Key, Pointer, PACDiscReg);
2478 };
2479
2480 // Emit checking and resigning as needed.
2481
2482 if (!SignSchema) {
2483 if (CheckMode == PtrauthCheckMode::Trap)
2484 EmitCheck();
2485 // For authentication-only pseudos, Poison is demoted to Unchecked.
2486 return;
2487 }
2488
2489 switch (CheckMode) {
2490 case PtrauthCheckMode::Unchecked:
2491 EmitResignOnSuccess();
2492 break;
2493 case PtrauthCheckMode::Trap:
2494 EmitCheck();
2495 EmitResignOnSuccess();
2496 break;
2497 case PtrauthCheckMode::Poison:
2498 MCSymbol *OnFailure = createTempSymbol("resign_end_");
2499 EmitCheck(OnFailure);
2500 EmitResignOnSuccess();
2501 OutStreamer->emitLabel(OnFailure);
2502 break;
2503 }
2504}
2505
2506void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) {
2507 Register Val = MI->getOperand(1).getReg();
2508 auto Key = (AArch64PACKey::ID)MI->getOperand(2).getImm();
2509 uint64_t Disc = MI->getOperand(3).getImm();
2510 Register AddrDisc = MI->getOperand(4).getReg();
2511 bool AddrDiscKilled = MI->getOperand(4).isKill();
2512
2513 // As long as at least one of Val and AddrDisc is in GPR64noip, a scratch
2514 // register is available.
2515 Register ScratchReg = Val == AArch64::X16 ? AArch64::X17 : AArch64::X16;
2516 assert(ScratchReg != AddrDisc &&
2517 "Neither X16 nor X17 is available as a scratch register");
2518
2519 // Compute pac discriminator
2520 Register DiscReg = emitPtrauthDiscriminator(
2521 Disc, AddrDisc, ScratchReg, /*MayClobberAddrDisc=*/AddrDiscKilled);
2522
2523 if (emitDeactivationSymbolRelocation(MI->getDeactivationSymbol()))
2524 return;
2525
2526 emitPAC(Key, Val, DiscReg);
2527}
2528
2529void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
2530 bool IsCall = MI->getOpcode() == AArch64::BLRA;
2531 unsigned BrTarget = MI->getOperand(0).getReg();
2532
2533 auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm();
2534 uint64_t Disc = MI->getOperand(2).getImm();
2535
2536 unsigned AddrDisc = MI->getOperand(3).getReg();
2537
2538 // Make sure AddrDisc is solely used to compute the discriminator.
2539 // While hardly meaningful, it is still possible to describe an authentication
2540 // of a pointer against its own value (instead of storage address) with
2541 // intrinsics, so use report_fatal_error instead of assert.
2542 if (BrTarget == AddrDisc)
2543 report_fatal_error("Branch target is signed with its own value");
2544
2545 // If we are printing BLRA pseudo, try to save one MOV by making use of the
2546 // fact that x16 and x17 are described as clobbered by the MI instruction and
2547 // AddrDisc is not used as any other input.
2548 //
2549 // Back in the day, emitPtrauthDiscriminator was restricted to only returning
2550 // either x16 or x17, meaning the returned register is always among the
2551 // implicit-def'ed registers of BLRA pseudo. Now this property can be violated
2552 // if isX16X17Safer predicate is false, thus manually check if AddrDisc is
2553 // among x16 and x17 to prevent clobbering unexpected registers.
2554 //
2555 // Unlike BLRA, BRA pseudo is used to perform computed goto, and thus not
2556 // declared as clobbering x16/x17.
2557 //
2558 // FIXME: Make use of `killed` flags and register masks instead.
2559 bool AddrDiscIsImplicitDef =
2560 IsCall && (AddrDisc == AArch64::X16 || AddrDisc == AArch64::X17);
2561 Register DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, AArch64::X17,
2562 AddrDiscIsImplicitDef);
2563 emitBLRA(IsCall, Key, BrTarget, DiscReg);
2564}
2565
2566void AArch64AsmPrinter::emitAddImm(MCRegister Reg, int64_t Addend,
2567 MCRegister Tmp) {
2568 if (Addend != 0) {
2569 const uint64_t AbsOffset = (Addend > 0 ? Addend : -((uint64_t)Addend));
2570 const bool IsNeg = Addend < 0;
2571 if (isUInt<24>(AbsOffset)) {
2572 for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
2573 BitPos += 12) {
2574 EmitToStreamer(
2575 MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri)
2576 .addReg(Reg)
2577 .addReg(Reg)
2578 .addImm((AbsOffset >> BitPos) & 0xfff)
2579 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
2580 }
2581 } else {
2582 const uint64_t UAddend = Addend;
2583 EmitToStreamer(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
2584 .addReg(Tmp)
2585 .addImm((IsNeg ? ~UAddend : UAddend) & 0xffff)
2586 .addImm(/*shift=*/0));
2587 auto NeedMovk = [IsNeg, UAddend](int BitPos) -> bool {
2588 assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
2589 uint64_t Shifted = UAddend >> BitPos;
2590 if (!IsNeg)
2591 return Shifted != 0;
2592 for (int I = 0; I != 64 - BitPos; I += 16)
2593 if (((Shifted >> I) & 0xffff) != 0xffff)
2594 return true;
2595 return false;
2596 };
2597 for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16)
2598 emitMOVK(Tmp, (UAddend >> BitPos) & 0xffff, BitPos);
2599
2600 EmitToStreamer(MCInstBuilder(AArch64::ADDXrs)
2601 .addReg(Reg)
2602 .addReg(Reg)
2603 .addReg(Tmp)
2604 .addImm(/*shift=*/0));
2605 }
2606 }
2607}
2608
2609void AArch64AsmPrinter::emitAddress(MCRegister Reg, const MCExpr *Expr,
2610 MCRegister Tmp, bool DSOLocal,
2611 const MCSubtargetInfo &STI) {
2612 MCValue Val;
2613 if (!Expr->evaluateAsRelocatable(Val, nullptr))
2614 report_fatal_error("emitAddress could not evaluate");
2615 if (DSOLocal) {
2616 EmitToStreamer(
2617 MCInstBuilder(AArch64::ADRP)
2618 .addReg(Reg)
2620 OutStreamer->getContext())));
2621 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
2622 .addReg(Reg)
2623 .addReg(Reg)
2624 .addExpr(MCSpecifierExpr::create(
2625 Expr, AArch64::S_LO12, OutStreamer->getContext()))
2626 .addImm(0));
2627 } else {
2628 auto *SymRef =
2629 MCSymbolRefExpr::create(Val.getAddSym(), OutStreamer->getContext());
2630 EmitToStreamer(
2631 MCInstBuilder(AArch64::ADRP)
2632 .addReg(Reg)
2634 OutStreamer->getContext())));
2635 EmitToStreamer(
2636 MCInstBuilder(AArch64::LDRXui)
2637 .addReg(Reg)
2638 .addReg(Reg)
2640 OutStreamer->getContext())));
2641 emitAddImm(Reg, Val.getConstant(), Tmp);
2642 }
2643}
2644
2646 // IFUNCs are ELF-only.
2647 if (!TT.isOSBinFormatELF())
2648 return false;
2649
2650 // IFUNCs are supported on glibc, bionic, and some but not all of the BSDs.
2651 return TT.isOSGlibc() || TT.isAndroid() || TT.isOSFreeBSD() ||
2652 TT.isOSDragonFly() || TT.isOSNetBSD();
2653}
2654
2655// Emit an ifunc resolver that returns a signed pointer to the specified target,
2656// and return a FUNCINIT reference to the resolver. In the linked binary, this
2657// function becomes the target of an IRELATIVE relocation. This resolver is used
2658// to relocate signed pointers in global variable initializers in special cases
2659// where the standard R_AARCH64_AUTH_ABS64 relocation would not work.
2660//
2661// Example (signed null pointer, not address discriminated):
2662//
2663// .8byte .Lpauth_ifunc0
2664// .pushsection .text.startup,"ax",@progbits
2665// .Lpauth_ifunc0:
2666// mov x0, #0
2667// mov x1, #12345
2668// b __emupac_pacda
2669//
2670// Example (signed null pointer, address discriminated):
2671//
2672// .Ltmp:
2673// .8byte .Lpauth_ifunc0
2674// .pushsection .text.startup,"ax",@progbits
2675// .Lpauth_ifunc0:
2676// mov x0, #0
2677// adrp x1, .Ltmp
2678// add x1, x1, :lo12:.Ltmp
2679// b __emupac_pacda
2680// .popsection
2681//
2682// Example (signed pointer to symbol, not address discriminated):
2683//
2684// .Ltmp:
2685// .8byte .Lpauth_ifunc0
2686// .pushsection .text.startup,"ax",@progbits
2687// .Lpauth_ifunc0:
2688// adrp x0, symbol
2689// add x0, x0, :lo12:symbol
2690// mov x1, #12345
2691// b __emupac_pacda
2692// .popsection
2693//
2694// Example (signed null pointer, not address discriminated, with deactivation
2695// symbol ds):
2696//
2697// .8byte .Lpauth_ifunc0
2698// .pushsection .text.startup,"ax",@progbits
2699// .Lpauth_ifunc0:
2700// mov x0, #0
2701// mov x1, #12345
2702// .reloc ., R_AARCH64_PATCHINST, ds
2703// b __emupac_pacda
2704// ret
2705// .popsection
2706const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative(
2707 const MCExpr *Target, uint64_t Disc, AArch64PACKey::ID KeyID,
2708 bool HasAddressDiversity, bool IsDSOLocal, const MCExpr *DSExpr) {
2709 const Triple &TT = TM.getTargetTriple();
2710
2711 // We only emit an IRELATIVE relocation if the target supports IRELATIVE.
2713 return nullptr;
2714
2715 // For now, only the DA key is supported.
2716 if (KeyID != AArch64PACKey::DA)
2717 return nullptr;
2718
2719 // AArch64Subtarget is huge, so heap allocate it so we don't run out of stack
2720 // space.
2721 auto STI = std::make_unique<AArch64Subtarget>(
2722 TT, TM.getTargetCPU(), TM.getTargetCPU(), TM.getTargetFeatureString(), TM,
2723 true);
2724 this->STI = STI.get();
2725
2726 MCSymbol *Place = OutStreamer->getContext().createTempSymbol();
2727 OutStreamer->emitLabel(Place);
2728 OutStreamer->pushSection();
2729
2730 const MCSymbolELF *Group =
2731 static_cast<MCSectionELF *>(OutStreamer->getCurrentSectionOnly())
2732 ->getGroup();
2734 if (Group)
2736 OutStreamer->switchSection(OutStreamer->getContext().getELFSection(
2737 ".text.startup", ELF::SHT_PROGBITS, Flags, 0, Group, true,
2738 Group ? MCSection::NonUniqueID : PAuthIFuncNextUniqueID++, nullptr));
2739
2740 MCSymbol *IRelativeSym =
2741 OutStreamer->getContext().createLinkerPrivateSymbol("pauth_ifunc");
2742 OutStreamer->emitLabel(IRelativeSym);
2743 if (isa<MCConstantExpr>(Target)) {
2744 OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
2745 .addReg(AArch64::X0)
2746 .addExpr(Target)
2747 .addImm(0),
2748 *STI);
2749 } else {
2750 emitAddress(AArch64::X0, Target, AArch64::X16, IsDSOLocal, *STI);
2751 }
2752 if (HasAddressDiversity) {
2753 auto *PlacePlusDisc = MCBinaryExpr::createAdd(
2754 MCSymbolRefExpr::create(Place, OutStreamer->getContext()),
2755 MCConstantExpr::create(Disc, OutStreamer->getContext()),
2756 OutStreamer->getContext());
2757 emitAddress(AArch64::X1, PlacePlusDisc, AArch64::X16, /*IsDSOLocal=*/true,
2758 *STI);
2759 } else {
2760 if (!isUInt<16>(Disc)) {
2761 OutContext.reportError(SMLoc(), "AArch64 PAC Discriminator '" +
2762 Twine(Disc) +
2763 "' out of range [0, 0xFFFF]");
2764 }
2765 emitMOVZ(AArch64::X1, Disc, 0);
2766 }
2767
2768 if (DSExpr) {
2769 MCSymbol *PrePACInst = OutStreamer->getContext().createTempSymbol();
2770 OutStreamer->emitLabel(PrePACInst);
2771
2772 auto *PrePACInstExpr =
2773 MCSymbolRefExpr::create(PrePACInst, OutStreamer->getContext());
2774 OutStreamer->emitRelocDirective(*PrePACInstExpr, "R_AARCH64_PATCHINST",
2775 DSExpr, SMLoc());
2776 }
2777
2778 // We don't know the subtarget because this is being emitted for a global
2779 // initializer. Because the performance of IFUNC resolvers is unimportant, we
2780 // always call the EmuPAC runtime, which will end up using the PAC instruction
2781 // if the target supports PAC.
2782 MCSymbol *EmuPAC =
2783 OutStreamer->getContext().getOrCreateSymbol("__emupac_pacda");
2784 const MCSymbolRefExpr *EmuPACRef =
2785 MCSymbolRefExpr::create(EmuPAC, OutStreamer->getContext());
2786 OutStreamer->emitInstruction(MCInstBuilder(AArch64::B).addExpr(EmuPACRef),
2787 *STI);
2788
2789 // We need a RET despite the above tail call because the deactivation symbol
2790 // may replace the tail call with a NOP.
2791 if (DSExpr)
2792 OutStreamer->emitInstruction(
2793 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
2794 OutStreamer->popSection();
2795
2797 MCSymbolRefExpr::create(IRelativeSym, OutStreamer->getContext()),
2798 AArch64::S_FUNCINIT, OutStreamer->getContext());
2799}
2800
2801const MCExpr *
2802AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2803 MCContext &Ctx = OutContext;
2804
2805 // Figure out the base symbol and the addend, if any.
2806 APInt Offset(64, 0);
2807 const Value *BaseGV = CPA.getPointer()->stripAndAccumulateConstantOffsets(
2808 getDataLayout(), Offset, /*AllowNonInbounds=*/true);
2809
2810 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
2811
2812 const MCExpr *Sym;
2813 if (BaseGVB) {
2814 // If there is an addend, turn that into the appropriate MCExpr.
2815 Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2816 if (Offset.sgt(0))
2818 Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2819 else if (Offset.slt(0))
2821 Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2822 } else if (isa<ConstantPointerNull>(BaseGV)) {
2823 Sym = MCConstantExpr::create(Offset.getSExtValue(), Ctx);
2824 } else {
2825 reportFatalUsageError("unsupported constant expression in ptrauth pointer");
2826 }
2827
2828 const MCExpr *DSExpr = nullptr;
2829 if (auto *DS = dyn_cast<GlobalValue>(CPA.getDeactivationSymbol())) {
2830 if (isa<GlobalAlias>(DS))
2831 return Sym;
2832 DSExpr = MCSymbolRefExpr::create(getSymbol(DS), Ctx);
2833 }
2834
2835 uint64_t KeyID = CPA.getKey()->getZExtValue();
2836 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
2837 // AArch64AuthMCExpr::printImpl, so fail fast.
2838 if (KeyID > AArch64PACKey::LAST) {
2839 CPA.getContext().emitError("AArch64 PAC Key ID '" + Twine(KeyID) +
2840 "' out of range [0, " +
2841 Twine((unsigned)AArch64PACKey::LAST) + "]");
2842 KeyID = 0;
2843 }
2844
2845 uint64_t Disc = CPA.getDiscriminator()->getZExtValue();
2846
2847 // Check if we can represent this with an IRELATIVE and emit it if so.
2848 if (auto *IFuncSym = emitPAuthRelocationAsIRelative(
2849 Sym, Disc, AArch64PACKey::ID(KeyID), CPA.hasAddressDiscriminator(),
2850 BaseGVB && BaseGVB->isDSOLocal(), DSExpr))
2851 return IFuncSym;
2852
2853 if (!isUInt<16>(Disc)) {
2854 CPA.getContext().emitError("AArch64 PAC Discriminator '" + Twine(Disc) +
2855 "' out of range [0, 0xFFFF]");
2856 Disc = 0;
2857 }
2858
2859 if (DSExpr)
2860 report_fatal_error("deactivation symbols unsupported in constant "
2861 "expressions on this target");
2862
2863 // Finally build the complete @AUTH expr.
2864 return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
2865 CPA.hasAddressDiscriminator(), Ctx);
2866}
2867
2868void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
2869 unsigned DstReg = MI.getOperand(0).getReg();
2870 const MachineOperand &GAOp = MI.getOperand(1);
2871 const uint64_t KeyC = MI.getOperand(2).getImm();
2872 assert(KeyC <= AArch64PACKey::LAST &&
2873 "key is out of range [0, AArch64PACKey::LAST]");
2874 const auto Key = (AArch64PACKey::ID)KeyC;
2875 const uint64_t Disc = MI.getOperand(3).getImm();
2876 assert(isUInt<16>(Disc) &&
2877 "constant discriminator is out of range [0, 0xffff]");
2878
2879 // Emit instruction sequence like the following:
2880 // ADRP x16, symbol$auth_ptr$key$disc
2881 // LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc]
2882 //
2883 // Where the $auth_ptr$ symbol is the stub slot containing the signed pointer
2884 // to symbol.
2885 MCSymbol *AuthPtrStubSym;
2886 if (TM.getTargetTriple().isOSBinFormatELF()) {
2887 const auto &TLOF =
2888 static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering());
2889
2890 assert(GAOp.getOffset() == 0 &&
2891 "non-zero offset for $auth_ptr$ stub slots is not supported");
2892 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
2893 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
2894 } else {
2895 assert(TM.getTargetTriple().isOSBinFormatMachO() &&
2896 "LOADauthptrstatic is implemented only for MachO/ELF");
2897
2898 const auto &TLOF = static_cast<const AArch64_MachoTargetObjectFile &>(
2899 getObjFileLowering());
2900
2901 assert(GAOp.getOffset() == 0 &&
2902 "non-zero offset for $auth_ptr$ stub slots is not supported");
2903 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
2904 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
2905 }
2906
2907 MachineOperand StubMOHi =
2909 MachineOperand StubMOLo = MachineOperand::CreateMCSymbol(
2910 AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2911 MCOperand StubMCHi, StubMCLo;
2912
2913 MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
2914 MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
2915
2916 EmitToStreamer(
2917 *OutStreamer,
2918 MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi));
2919
2920 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui)
2921 .addReg(DstReg)
2922 .addReg(DstReg)
2923 .addOperand(StubMCLo));
2924}
2925
2926void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2927 const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC;
2928 const bool IsELFSignedGOT = MI.getParent()
2929 ->getParent()
2930 ->getInfo<AArch64FunctionInfo>()
2931 ->hasELFSignedGOT();
2932 MachineOperand GAOp = MI.getOperand(0);
2933 const uint64_t KeyC = MI.getOperand(1).getImm();
2934 assert(KeyC <= AArch64PACKey::LAST &&
2935 "key is out of range [0, AArch64PACKey::LAST]");
2936 const auto Key = (AArch64PACKey::ID)KeyC;
2937 const unsigned AddrDisc = MI.getOperand(2).getReg();
2938 const uint64_t Disc = MI.getOperand(3).getImm();
2939
2940 const int64_t Offset = GAOp.getOffset();
2941 GAOp.setOffset(0);
2942
2943 // Emit:
2944 // target materialization:
2945 // - via GOT:
2946 // - unsigned GOT:
2947 // adrp x16, :got:target
2948 // ldr x16, [x16, :got_lo12:target]
2949 // add offset to x16 if offset != 0
2950 // - ELF signed GOT:
2951 // adrp x17, :got:target
2952 // add x17, x17, :got_auth_lo12:target
2953 // ldr x16, [x17]
2954 // aut{i|d}a x16, x17
2955 // check+trap sequence (if no FPAC)
2956 // add offset to x16 if offset != 0
2957 //
2958 // - direct:
2959 // adrp x16, target
2960 // add x16, x16, :lo12:target
2961 // add offset to x16 if offset != 0
2962 //
2963 // add offset to x16:
2964 // - abs(offset) fits 24 bits:
2965 // add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions)
2966 // - abs(offset) does not fit 24 bits:
2967 // - offset < 0:
2968 // movn+movk sequence filling x17 register with the offset (up to 4
2969 // instructions)
2970 // add x16, x16, x17
2971 // - offset > 0:
2972 // movz+movk sequence filling x17 register with the offset (up to 4
2973 // instructions)
2974 // add x16, x16, x17
2975 //
2976 // signing:
2977 // - 0 discriminator:
2978 // paciza x16
2979 // - Non-0 discriminator, no address discriminator:
2980 // mov x17, #Disc
2981 // pacia x16, x17
2982 // - address discriminator (with potentially folded immediate discriminator):
2983 // pacia x16, xAddrDisc
2984
2985 MachineOperand GAMOHi(GAOp), GAMOLo(GAOp);
2986 MCOperand GAMCHi, GAMCLo;
2987
2988 GAMOHi.setTargetFlags(AArch64II::MO_PAGE);
2989 GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2990 if (IsGOTLoad) {
2991 GAMOHi.addTargetFlag(AArch64II::MO_GOT);
2992 GAMOLo.addTargetFlag(AArch64II::MO_GOT);
2993 }
2994
2995 MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
2996 MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
2997
2998 EmitToStreamer(
2999 MCInstBuilder(AArch64::ADRP)
3000 .addReg(IsGOTLoad && IsELFSignedGOT ? AArch64::X17 : AArch64::X16)
3001 .addOperand(GAMCHi));
3002
3003 if (IsGOTLoad) {
3004 if (IsELFSignedGOT) {
3005 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
3006 .addReg(AArch64::X17)
3007 .addReg(AArch64::X17)
3008 .addOperand(GAMCLo)
3009 .addImm(0));
3010
3011 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
3012 .addReg(AArch64::X16)
3013 .addReg(AArch64::X17)
3014 .addImm(0));
3015
3016 assert(GAOp.isGlobal());
3017 assert(GAOp.getGlobal()->getValueType() != nullptr);
3018
3019 bool IsFunctionTy = GAOp.getGlobal()->getValueType()->isFunctionTy();
3020 auto AuthKey = IsFunctionTy ? AArch64PACKey::IA : AArch64PACKey::DA;
3021 emitAUT(AuthKey, AArch64::X16, AArch64::X17);
3022
3023 if (!STI->hasFPAC())
3024 emitPtrauthCheckAuthenticatedValue(AArch64::X16, AArch64::X17, AuthKey,
3025 AArch64PAuth::AuthCheckMethod::XPAC);
3026 } else {
3027 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
3028 .addReg(AArch64::X16)
3029 .addReg(AArch64::X16)
3030 .addOperand(GAMCLo));
3031 }
3032 } else {
3033 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
3034 .addReg(AArch64::X16)
3035 .addReg(AArch64::X16)
3036 .addOperand(GAMCLo)
3037 .addImm(0));
3038 }
3039
3040 emitAddImm(AArch64::X16, Offset, AArch64::X17);
3041 Register DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, AArch64::X17);
3042
3043 emitPAC(Key, AArch64::X16, DiscReg);
3044}
3045
3046void AArch64AsmPrinter::LowerLOADgotAUTH(const MachineInstr &MI) {
3047 Register DstReg = MI.getOperand(0).getReg();
3048 Register AuthResultReg = STI->hasFPAC() ? DstReg : AArch64::X16;
3049 const MachineOperand &GAMO = MI.getOperand(1);
3050 assert(GAMO.getOffset() == 0);
3051
3052 if (MI.getMF()->getTarget().getCodeModel() == CodeModel::Tiny) {
3053 MCOperand GAMC;
3054 MCInstLowering.lowerOperand(GAMO, GAMC);
3055 EmitToStreamer(
3056 MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addOperand(GAMC));
3057 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
3058 .addReg(AuthResultReg)
3059 .addReg(AArch64::X17)
3060 .addImm(0));
3061 } else {
3062 MachineOperand GAHiOp(GAMO);
3063 MachineOperand GALoOp(GAMO);
3064 GAHiOp.addTargetFlag(AArch64II::MO_PAGE);
3065 GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
3066
3067 MCOperand GAMCHi, GAMCLo;
3068 MCInstLowering.lowerOperand(GAHiOp, GAMCHi);
3069 MCInstLowering.lowerOperand(GALoOp, GAMCLo);
3070
3071 EmitToStreamer(
3072 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(GAMCHi));
3073
3074 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
3075 .addReg(AArch64::X17)
3076 .addReg(AArch64::X17)
3077 .addOperand(GAMCLo)
3078 .addImm(0));
3079
3080 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
3081 .addReg(AuthResultReg)
3082 .addReg(AArch64::X17)
3083 .addImm(0));
3084 }
3085
3086 assert(GAMO.isGlobal());
3087 MCSymbol *UndefWeakSym;
3088 if (GAMO.getGlobal()->hasExternalWeakLinkage()) {
3089 UndefWeakSym = createTempSymbol("undef_weak");
3090 EmitToStreamer(
3091 MCInstBuilder(AArch64::CBZX)
3092 .addReg(AuthResultReg)
3093 .addExpr(MCSymbolRefExpr::create(UndefWeakSym, OutContext)));
3094 }
3095
3096 assert(GAMO.getGlobal()->getValueType() != nullptr);
3097
3098 bool IsFunctionTy = GAMO.getGlobal()->getValueType()->isFunctionTy();
3099 auto AuthKey = IsFunctionTy ? AArch64PACKey::IA : AArch64PACKey::DA;
3100 emitAUT(AuthKey, AuthResultReg, AArch64::X17);
3101
3102 if (GAMO.getGlobal()->hasExternalWeakLinkage())
3103 OutStreamer->emitLabel(UndefWeakSym);
3104
3105 if (!STI->hasFPAC()) {
3106 emitPtrauthCheckAuthenticatedValue(AuthResultReg, AArch64::X17, AuthKey,
3107 AArch64PAuth::AuthCheckMethod::XPAC);
3108
3109 emitMovXReg(DstReg, AuthResultReg);
3110 }
3111}
3112
3113const MCExpr *
3114AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) {
3115 const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant(BA);
3116 const Function &Fn = *BA.getFunction();
3117
3118 if (std::optional<uint16_t> BADisc =
3119 STI->getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn))
3120 return AArch64AuthMCExpr::create(BAE, *BADisc, AArch64PACKey::IA,
3121 /*HasAddressDiversity=*/false, OutContext);
3122
3123 return BAE;
3124}
3125
3126void AArch64AsmPrinter::emitCBPseudoExpansion(const MachineInstr *MI) {
3127 bool IsImm = false;
3128 unsigned Width = 0;
3129
3130 switch (MI->getOpcode()) {
3131 default:
3132 llvm_unreachable("This is not a CB pseudo instruction");
3133 case AArch64::CBBAssertExt:
3134 IsImm = false;
3135 Width = 8;
3136 break;
3137 case AArch64::CBHAssertExt:
3138 IsImm = false;
3139 Width = 16;
3140 break;
3141 case AArch64::CBWPrr:
3142 Width = 32;
3143 break;
3144 case AArch64::CBXPrr:
3145 Width = 64;
3146 break;
3147 case AArch64::CBWPri:
3148 IsImm = true;
3149 Width = 32;
3150 break;
3151 case AArch64::CBXPri:
3152 IsImm = true;
3153 Width = 64;
3154 break;
3155 }
3156
3158 static_cast<AArch64CC::CondCode>(MI->getOperand(0).getImm());
3159 bool NeedsRegSwap = false;
3160 bool NeedsImmDec = false;
3161 bool NeedsImmInc = false;
3162
3163#define GET_CB_OPC(IsImm, Width, ImmCond, RegCond) \
3164 (IsImm \
3165 ? (Width == 32 ? AArch64::CB##ImmCond##Wri : AArch64::CB##ImmCond##Xri) \
3166 : (Width == 8 \
3167 ? AArch64::CBB##RegCond##Wrr \
3168 : (Width == 16 ? AArch64::CBH##RegCond##Wrr \
3169 : (Width == 32 ? AArch64::CB##RegCond##Wrr \
3170 : AArch64::CB##RegCond##Xrr))))
3171 unsigned MCOpC;
3172
3173 // Decide if we need to either swap register operands or increment/decrement
3174 // immediate operands
3175 switch (CC) {
3176 default:
3177 llvm_unreachable("Invalid CB condition code");
3178 case AArch64CC::EQ:
3179 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ EQ, /* Reg-Reg */ EQ);
3180 break;
3181 case AArch64CC::NE:
3182 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ NE, /* Reg-Reg */ NE);
3183 break;
3184 case AArch64CC::HS:
3185 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ HI, /* Reg-Reg */ HS);
3186 NeedsImmDec = IsImm;
3187 break;
3188 case AArch64CC::LO:
3189 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LO, /* Reg-Reg */ HI);
3190 NeedsRegSwap = !IsImm;
3191 break;
3192 case AArch64CC::HI:
3193 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ HI, /* Reg-Reg */ HI);
3194 break;
3195 case AArch64CC::LS:
3196 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LO, /* Reg-Reg */ HS);
3197 NeedsRegSwap = !IsImm;
3198 NeedsImmInc = IsImm;
3199 break;
3200 case AArch64CC::GE:
3201 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ GT, /* Reg-Reg */ GE);
3202 NeedsImmDec = IsImm;
3203 break;
3204 case AArch64CC::LT:
3205 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LT, /* Reg-Reg */ GT);
3206 NeedsRegSwap = !IsImm;
3207 break;
3208 case AArch64CC::GT:
3209 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ GT, /* Reg-Reg */ GT);
3210 break;
3211 case AArch64CC::LE:
3212 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LT, /* Reg-Reg */ GE);
3213 NeedsRegSwap = !IsImm;
3214 NeedsImmInc = IsImm;
3215 break;
3216 }
3217#undef GET_CB_OPC
3218
3219 MCInst Inst;
3220 Inst.setOpcode(MCOpC);
3221
3222 MCOperand Lhs, Rhs, Trgt;
3223 lowerOperand(MI->getOperand(1), Lhs);
3224 lowerOperand(MI->getOperand(2), Rhs);
3225 lowerOperand(MI->getOperand(3), Trgt);
3226
3227 // Now swap, increment or decrement
3228 if (NeedsRegSwap) {
3229 assert(Lhs.isReg() && "Expected register operand for CB");
3230 assert(Rhs.isReg() && "Expected register operand for CB");
3231 Inst.addOperand(Rhs);
3232 Inst.addOperand(Lhs);
3233 } else if (NeedsImmDec) {
3234 Rhs.setImm(Rhs.getImm() - 1);
3235 Inst.addOperand(Lhs);
3236 Inst.addOperand(Rhs);
3237 } else if (NeedsImmInc) {
3238 Rhs.setImm(Rhs.getImm() + 1);
3239 Inst.addOperand(Lhs);
3240 Inst.addOperand(Rhs);
3241 } else {
3242 Inst.addOperand(Lhs);
3243 Inst.addOperand(Rhs);
3244 }
3245
3246 assert((!IsImm || (Rhs.getImm() >= 0 && Rhs.getImm() < 64)) &&
3247 "CB immediate operand out-of-bounds");
3248
3249 Inst.addOperand(Trgt);
3250 EmitToStreamer(*OutStreamer, Inst);
3251}
3252
3253void AArch64AsmPrinter::emitAtomicHintPseudoExpansion(const MachineInstr *MI) {
3254
3255 unsigned StOpc;
3256 unsigned Relaxed = MI->getOperand(2).getImm();
3257 assert(Relaxed < 2 && "Atomic hint relaxed immediate out-of-bounds");
3258 switch (MI->getOpcode()) {
3259 case AArch64::ATOMIC_STORE_HINT_B:
3260 StOpc = Relaxed ? AArch64::STRBBui : AArch64::STLRB;
3261 break;
3262 case AArch64::ATOMIC_STORE_HINT_H:
3263 StOpc = Relaxed ? AArch64::STRHHui : AArch64::STLRH;
3264 break;
3265 case AArch64::ATOMIC_STORE_HINT_W:
3266 StOpc = Relaxed ? AArch64::STRWui : AArch64::STLRW;
3267 break;
3268 case AArch64::ATOMIC_STORE_HINT_X:
3269 StOpc = Relaxed ? AArch64::STRXui : AArch64::STLRX;
3270 break;
3271 default:
3272 llvm_unreachable("Unexpected atomic hint size.");
3273 }
3274
3275 EmitToStreamer(
3276 MCInstBuilder(AArch64::HINT).addImm(MI->getOperand(3).getImm()));
3277
3278 MCInst Store;
3279 Store.setOpcode(StOpc);
3280 Store.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
3281 Store.addOperand(MCOperand::createReg(MI->getOperand(1).getReg()));
3282 Store.setFlags(MI->getFlags());
3283 if (Relaxed)
3284 Store.addOperand(MCOperand::createImm(0));
3285 EmitToStreamer(*OutStreamer, Store);
3286}
3287
3288void AArch64AsmPrinter::emitAtomicHintPseudoExpansionRO(
3289 const MachineInstr *MI) {
3290 unsigned StOpc;
3291 assert(MI->getOperand(5).getImm() == 1 &&
3292 "Atomic store addressing mode only supports relaxed stores");
3293
3294 switch (MI->getOpcode()) {
3295 case AArch64::ATOMIC_STORE_HINT_BroW:
3296 StOpc = AArch64::STRBBroW;
3297 break;
3298 case AArch64::ATOMIC_STORE_HINT_HroW:
3299 StOpc = AArch64::STRHHroW;
3300 break;
3301 case AArch64::ATOMIC_STORE_HINT_WroW:
3302 StOpc = AArch64::STRWroW;
3303 break;
3304 case AArch64::ATOMIC_STORE_HINT_XroW:
3305 StOpc = AArch64::STRXroW;
3306 break;
3307 case AArch64::ATOMIC_STORE_HINT_SroW:
3308 StOpc = AArch64::STRSroW;
3309 break;
3310 case AArch64::ATOMIC_STORE_HINT_DroW:
3311 StOpc = AArch64::STRDroW;
3312 break;
3313 case AArch64::ATOMIC_STORE_HINT_BroX:
3314 StOpc = AArch64::STRBBroX;
3315 break;
3316 case AArch64::ATOMIC_STORE_HINT_HroX:
3317 StOpc = AArch64::STRHHroX;
3318 break;
3319 case AArch64::ATOMIC_STORE_HINT_WroX:
3320 StOpc = AArch64::STRWroX;
3321 break;
3322 case AArch64::ATOMIC_STORE_HINT_XroX:
3323 StOpc = AArch64::STRXroX;
3324 break;
3325 case AArch64::ATOMIC_STORE_HINT_SroX:
3326 StOpc = AArch64::STRSroX;
3327 break;
3328 case AArch64::ATOMIC_STORE_HINT_DroX:
3329 StOpc = AArch64::STRDroX;
3330 break;
3331 default:
3332 llvm_unreachable("Unexpected atomic hint opcode.");
3333 }
3334
3335 EmitToStreamer(
3336 MCInstBuilder(AArch64::HINT).addImm(MI->getOperand(6).getImm()));
3337
3338 MCInst Store;
3339 Store.setOpcode(StOpc);
3340 Store.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); // Rn
3341 Store.addOperand(MCOperand::createReg(MI->getOperand(1).getReg())); // Rm
3342 Store.addOperand(MCOperand::createReg(MI->getOperand(2).getReg())); // Data
3343 Store.addOperand(MCOperand::createImm(MI->getOperand(3).getImm())); // Signed
3344 Store.addOperand(MCOperand::createImm(MI->getOperand(4).getImm())); // Shift
3345 Store.setFlags(MI->getFlags());
3346 EmitToStreamer(*OutStreamer, Store);
3347}
3348
3349void AArch64AsmPrinter::emitAtomicHintPseudoExpansionImm(
3350 const MachineInstr *MI) {
3351 unsigned StOpc;
3352 assert(MI->getOperand(3).getImm() == 1 &&
3353 "Atomic store addressing mode only supports relaxed stores");
3354
3355 switch (MI->getOpcode()) {
3356 case AArch64::ATOMIC_STORE_HINT_Bui:
3357 StOpc = AArch64::STRBBui;
3358 break;
3359 case AArch64::ATOMIC_STORE_HINT_Hui:
3360 StOpc = AArch64::STRHHui;
3361 break;
3362 case AArch64::ATOMIC_STORE_HINT_Wui:
3363 StOpc = AArch64::STRWui;
3364 break;
3365 case AArch64::ATOMIC_STORE_HINT_Xui:
3366 StOpc = AArch64::STRXui;
3367 break;
3368 case AArch64::ATOMIC_STORE_HINT_Sui:
3369 StOpc = AArch64::STRSui;
3370 break;
3371 case AArch64::ATOMIC_STORE_HINT_Dui:
3372 StOpc = AArch64::STRDui;
3373 break;
3374 case AArch64::ATOMIC_STORE_HINT_Bi:
3375 StOpc = AArch64::STURBBi;
3376 break;
3377 case AArch64::ATOMIC_STORE_HINT_Hi:
3378 StOpc = AArch64::STURHHi;
3379 break;
3380 case AArch64::ATOMIC_STORE_HINT_Wi:
3381 StOpc = AArch64::STURWi;
3382 break;
3383 case AArch64::ATOMIC_STORE_HINT_Xi:
3384 StOpc = AArch64::STURXi;
3385 break;
3386 case AArch64::ATOMIC_STORE_HINT_Si:
3387 StOpc = AArch64::STURSi;
3388 break;
3389 case AArch64::ATOMIC_STORE_HINT_Di:
3390 StOpc = AArch64::STURDi;
3391 break;
3392 default:
3393 llvm_unreachable("Unexpected atomic hint opcode.");
3394 }
3395
3396 EmitToStreamer(
3397 MCInstBuilder(AArch64::HINT).addImm(MI->getOperand(4).getImm()));
3398
3399 MCInst Store;
3400 Store.setOpcode(StOpc);
3401 Store.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); // Rn
3402 Store.addOperand(MCOperand::createReg(MI->getOperand(1).getReg())); // Data
3403 Store.addOperand(MCOperand::createImm(MI->getOperand(2).getImm())); // Imm
3404 Store.setFlags(MI->getFlags());
3405 EmitToStreamer(*OutStreamer, Store);
3406}
3407
3408void AArch64AsmPrinter::emitAtomicFetchHintPseudoExpansion(
3409 const MachineInstr *MI) {
3410 EmitToStreamer(
3411 MCInstBuilder(AArch64::HINT).addImm(MI->getOperand(4).getImm()));
3412
3413 MCInst Fetch;
3414 Fetch.setOpcode(MI->getOperand(3).getImm());
3415 Fetch.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
3416 Fetch.addOperand(MCOperand::createReg(MI->getOperand(1).getReg()));
3417 Fetch.addOperand(MCOperand::createReg(MI->getOperand(2).getReg()));
3418 Fetch.setFlags(MI->getFlags());
3419 EmitToStreamer(*OutStreamer, Fetch);
3420}
3421
3422// Simple pseudo-instructions have their lowering (with expansion to real
3423// instructions) auto-generated.
3424#include "AArch64GenMCPseudoLowering.inc"
3425
3426void AArch64AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
3427 S.emitInstruction(Inst, *STI);
3428#ifndef NDEBUG
3429 ++InstsEmitted;
3430#endif
3431}
3432
3433void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
3434 AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
3435
3436#ifndef NDEBUG
3437 InstsEmitted = 0;
3438 llvm::scope_exit CheckMISize([&]() {
3439 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
3440 });
3441#endif
3442
3443 // Do any auto-generated pseudo lowerings.
3444 if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {
3445 EmitToStreamer(*OutStreamer, OutInst);
3446 return;
3447 }
3448
3449 if (MI->getOpcode() == AArch64::ADRP) {
3450 for (auto &Opd : MI->operands()) {
3451 if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) ==
3452 "swift_async_extendedFramePointerFlags") {
3453 ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true;
3454 }
3455 }
3456 }
3457
3458 if (AArch64FI->getLOHRelated().count(MI)) {
3459 // Generate a label for LOH related instruction
3460 MCSymbol *LOHLabel = createTempSymbol("loh");
3461 // Associate the instruction with the label
3462 LOHInstToLabel[MI] = LOHLabel;
3463 OutStreamer->emitLabel(LOHLabel);
3464 }
3465
3466 AArch64TargetStreamer *TS =
3467 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
3468 // Do any manual lowerings.
3469 switch (MI->getOpcode()) {
3470 default:
3472 "Unhandled tail call instruction");
3473 break;
3474 case AArch64::READ_REGISTER_GPR64:
3475 // Read of a named GPR: emit "mov Xt, Xn" (ORR Xt, XZR, Xn). The source
3476 // register is encoded as an immediate operand so that earlier passes do not
3477 // see a use of an undefined physical register.
3478 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
3479 .addReg(MI->getOperand(0).getReg())
3480 .addReg(AArch64::XZR)
3481 .addReg(MI->getOperand(1).getImm())
3482 .addImm(0));
3483 return;
3484 case AArch64::READ_REGISTER_FPR64:
3485 // Read of a named FP/SIMD d-register: emit "fmov Dt, Dn".
3486 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::FMOVDr)
3487 .addReg(MI->getOperand(0).getReg())
3488 .addReg(MI->getOperand(1).getImm()));
3489 return;
3490 case AArch64::HINT: {
3491 // CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for
3492 // -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be
3493 // non-empty. If MI is the initial BTI, place the
3494 // __patchable_function_entries label after BTI.
3495 if (CurrentPatchableFunctionEntrySym &&
3496 CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
3497 MI == &MF->front().front()) {
3498 int64_t Imm = MI->getOperand(0).getImm();
3499 if (Imm == 32 || Imm == 34 || Imm == 36 || Imm == 38) {
3500 MCInst Inst;
3501 MCInstLowering.Lower(MI, Inst);
3502 EmitToStreamer(*OutStreamer, Inst);
3503 CurrentPatchableFunctionEntrySym = createTempSymbol("patch");
3504 OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym);
3505 return;
3506 }
3507 }
3508 break;
3509 }
3510 case AArch64::MOVMCSym: {
3511 Register DestReg = MI->getOperand(0).getReg();
3512 const MachineOperand &MO_Sym = MI->getOperand(1);
3513 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
3514 MCOperand Hi_MCSym, Lo_MCSym;
3515
3516 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
3517 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
3518
3519 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
3520 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
3521
3522 MCInst MovZ;
3523 MovZ.setOpcode(AArch64::MOVZXi);
3524 MovZ.addOperand(MCOperand::createReg(DestReg));
3525 MovZ.addOperand(Hi_MCSym);
3527 EmitToStreamer(*OutStreamer, MovZ);
3528
3529 MCInst MovK;
3530 MovK.setOpcode(AArch64::MOVKXi);
3531 MovK.addOperand(MCOperand::createReg(DestReg));
3532 MovK.addOperand(MCOperand::createReg(DestReg));
3533 MovK.addOperand(Lo_MCSym);
3535 EmitToStreamer(*OutStreamer, MovK);
3536 return;
3537 }
3538 case AArch64::MOVIv2d_ns:
3539 // It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0".
3540 // as movi is more efficient across all cores. Newer cores can eliminate
3541 // fmovs early and there is no difference with movi, but this not true for
3542 // all implementations.
3543 //
3544 // The floating-point version doesn't quite work in rare cases on older
3545 // CPUs, so on those targets we lower this instruction to movi.16b instead.
3546 if (STI->hasZeroCycleZeroingFPWorkaround() &&
3547 MI->getOperand(1).getImm() == 0) {
3548 MCInst TmpInst;
3549 TmpInst.setOpcode(AArch64::MOVIv16b_ns);
3550 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
3551 TmpInst.addOperand(MCOperand::createImm(0));
3552 EmitToStreamer(*OutStreamer, TmpInst);
3553 return;
3554 }
3555 break;
3556
3557 case AArch64::DBG_VALUE:
3558 case AArch64::DBG_VALUE_LIST:
3559 if (isVerbose() && OutStreamer->hasRawTextSupport()) {
3560 SmallString<128> TmpStr;
3561 raw_svector_ostream OS(TmpStr);
3562 PrintDebugValueComment(MI, OS);
3563 OutStreamer->emitRawText(StringRef(OS.str()));
3564 }
3565 return;
3566
3567 case AArch64::EMITBKEY: {
3568 ExceptionHandling ExceptionHandlingType = MAI.getExceptionHandlingType();
3569 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
3570 ExceptionHandlingType != ExceptionHandling::ARM)
3571 return;
3572
3573 if (getFunctionCFISectionType(*MF) == CFISection::None)
3574 return;
3575
3576 OutStreamer->emitCFIBKeyFrame();
3577 return;
3578 }
3579
3580 case AArch64::EMITMTETAGGED: {
3581 ExceptionHandling ExceptionHandlingType = MAI.getExceptionHandlingType();
3582 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
3583 ExceptionHandlingType != ExceptionHandling::ARM)
3584 return;
3585
3586 if (getFunctionCFISectionType(*MF) != CFISection::None)
3587 OutStreamer->emitCFIMTETaggedFrame();
3588 return;
3589 }
3590
3591 case AArch64::AUTx16x17: {
3592 const Register Pointer = AArch64::X16;
3593 const Register Scratch = AArch64::X17;
3594
3595 auto AuthSchema = PtrAuthSchema::CreateImmReg(
3596 (AArch64PACKey::ID)MI->getOperand(0).getImm(),
3597 MI->getOperand(1).getImm(), MI->getOperand(2));
3598
3599 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, std::nullopt,
3600 std::nullopt, MI->getDeactivationSymbol());
3601 return;
3602 }
3603
3604 case AArch64::AUTxMxN: {
3605 const Register Pointer = MI->getOperand(0).getReg();
3606 const Register Scratch = MI->getOperand(1).getReg();
3607
3608 auto AuthSchema = PtrAuthSchema::CreateImmReg(
3609 (AArch64PACKey::ID)MI->getOperand(3).getImm(),
3610 MI->getOperand(4).getImm(), MI->getOperand(5));
3611
3612 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, std::nullopt,
3613 std::nullopt, MI->getDeactivationSymbol());
3614 return;
3615 }
3616
3617 case AArch64::AUTPAC: {
3618 const Register Pointer = AArch64::X16;
3619 const Register Scratch = AArch64::X17;
3620
3621 auto AuthSchema = PtrAuthSchema::CreateImmReg(
3622 (AArch64PACKey::ID)MI->getOperand(0).getImm(),
3623 MI->getOperand(1).getImm(), MI->getOperand(2));
3624
3625 auto SignSchema = PtrAuthSchema::CreateImmReg(
3626 (AArch64PACKey::ID)MI->getOperand(3).getImm(),
3627 MI->getOperand(4).getImm(), MI->getOperand(5));
3628
3629 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, SignSchema,
3630 std::nullopt, MI->getDeactivationSymbol());
3631 return;
3632 }
3633
3634 case AArch64::AUTPCPAC: {
3635 auto AuthSchema = PtrAuthSchema::CreateRegReg(
3636 (AArch64PACKey::ID)MI->getOperand(0).getImm(), AArch64::X16,
3637 AArch64::X15);
3638
3639 auto SignSchema = PtrAuthSchema::CreateImmReg(
3640 (AArch64PACKey::ID)MI->getOperand(1).getImm(),
3641 MI->getOperand(2).getImm(), MI->getOperand(3));
3642
3643 emitPtrauthAuthResign(/*Pointer=*/AArch64::X17, /*Scratch=*/AArch64::X16,
3644 AuthSchema, SignSchema, std::nullopt,
3645 MI->getDeactivationSymbol());
3646 return;
3647 }
3648
3649 case AArch64::AUTRELLOADPAC: {
3650 const Register Pointer = AArch64::X16;
3651 const Register Scratch = AArch64::X17;
3652
3653 auto AuthSchema = PtrAuthSchema::CreateImmReg(
3654 (AArch64PACKey::ID)MI->getOperand(0).getImm(),
3655 MI->getOperand(1).getImm(), MI->getOperand(2));
3656
3657 auto SignSchema = PtrAuthSchema::CreateImmReg(
3658 (AArch64PACKey::ID)MI->getOperand(3).getImm(),
3659 MI->getOperand(4).getImm(), MI->getOperand(5));
3660
3661 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, SignSchema,
3662 MI->getOperand(6).getImm(),
3663 MI->getDeactivationSymbol());
3664
3665 return;
3666 }
3667
3668 case AArch64::PAC:
3669 emitPtrauthSign(MI);
3670 return;
3671
3672 case AArch64::LOADauthptrstatic:
3673 LowerLOADauthptrstatic(*MI);
3674 return;
3675
3676 case AArch64::LOADgotPAC:
3677 case AArch64::MOVaddrPAC:
3678 LowerMOVaddrPAC(*MI);
3679 return;
3680
3681 case AArch64::LOADgotAUTH:
3682 LowerLOADgotAUTH(*MI);
3683 return;
3684
3685 case AArch64::BRA:
3686 case AArch64::BLRA:
3687 emitPtrauthBranch(MI);
3688 return;
3689
3690 // Tail calls use pseudo instructions so they have the proper code-gen
3691 // attributes (isCall, isReturn, etc.). We lower them to the real
3692 // instruction here.
3693 case AArch64::AUTH_TCRETURN:
3694 case AArch64::AUTH_TCRETURN_BTI: {
3695 Register Callee = MI->getOperand(0).getReg();
3696 const auto Key = (AArch64PACKey::ID)MI->getOperand(2).getImm();
3697 const uint64_t Disc = MI->getOperand(3).getImm();
3698
3699 Register AddrDisc = MI->getOperand(4).getReg();
3700
3701 Register ScratchReg = Callee == AArch64::X16 ? AArch64::X17 : AArch64::X16;
3702
3703 emitPtrauthTailCallHardening(MI);
3704
3705 // See the comments in emitPtrauthBranch.
3706 if (Callee == AddrDisc)
3707 report_fatal_error("Call target is signed with its own value");
3708
3709 // After isX16X17Safer predicate was introduced, emitPtrauthDiscriminator is
3710 // no longer restricted to only reusing AddrDisc when it is X16 or X17
3711 // (which are implicit-def'ed by AUTH_TCRETURN pseudos), thus impose this
3712 // restriction manually not to clobber an unexpected register.
3713 bool AddrDiscIsImplicitDef =
3714 AddrDisc == AArch64::X16 || AddrDisc == AArch64::X17;
3715 Register DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, ScratchReg,
3716 AddrDiscIsImplicitDef);
3717 emitBLRA(/*IsCall*/ false, Key, Callee, DiscReg);
3718 return;
3719 }
3720
3721 case AArch64::TCRETURNri:
3722 case AArch64::TCRETURNrix16x17:
3723 case AArch64::TCRETURNrix17:
3724 case AArch64::TCRETURNrinotx16:
3725 case AArch64::TCRETURNriALL: {
3726 emitPtrauthTailCallHardening(MI);
3727
3728 recordIfImportCall(MI);
3729 MCInst TmpInst;
3730 TmpInst.setOpcode(AArch64::BR);
3731 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
3732 EmitToStreamer(*OutStreamer, TmpInst);
3733 return;
3734 }
3735 case AArch64::TCRETURNdi: {
3736 emitPtrauthTailCallHardening(MI);
3737
3738 MCOperand Dest;
3739 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
3740 recordIfImportCall(MI);
3741 MCInst TmpInst;
3742 TmpInst.setOpcode(AArch64::B);
3743 TmpInst.addOperand(Dest);
3744 EmitToStreamer(*OutStreamer, TmpInst);
3745 return;
3746 }
3747 case AArch64::SpeculationBarrierISBDSBEndBB: {
3748 // Print DSB SYS + ISB
3749 MCInst TmpInstDSB;
3750 TmpInstDSB.setOpcode(AArch64::DSB);
3751 TmpInstDSB.addOperand(MCOperand::createImm(0xf));
3752 EmitToStreamer(*OutStreamer, TmpInstDSB);
3753 MCInst TmpInstISB;
3754 TmpInstISB.setOpcode(AArch64::ISB);
3755 TmpInstISB.addOperand(MCOperand::createImm(0xf));
3756 EmitToStreamer(*OutStreamer, TmpInstISB);
3757 return;
3758 }
3759 case AArch64::SpeculationBarrierSBEndBB: {
3760 // Print SB
3761 MCInst TmpInstSB;
3762 TmpInstSB.setOpcode(AArch64::SB);
3763 EmitToStreamer(*OutStreamer, TmpInstSB);
3764 return;
3765 }
3766 case AArch64::TLSDESC_AUTH_CALLSEQ: {
3767 /// lower this to:
3768 /// adrp x0, :tlsdesc_auth:var
3769 /// ldr x16, [x0, #:tlsdesc_auth_lo12:var]
3770 /// add x0, x0, #:tlsdesc_auth_lo12:var
3771 /// .tlsauthdesccall var
3772 /// blraa x16, x0
3773 /// (TPIDR_EL0 offset now in x0)
3774 const MachineOperand &MO_Sym = MI->getOperand(0);
3775 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
3776 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
3777 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
3778 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
3779 MCInstLowering.lowerOperand(MO_Sym, Sym);
3780 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
3781 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
3782
3783 MCInst Adrp;
3784 Adrp.setOpcode(AArch64::ADRP);
3785 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
3786 Adrp.addOperand(SymTLSDesc);
3787 EmitToStreamer(*OutStreamer, Adrp);
3788
3789 MCInst Ldr;
3790 Ldr.setOpcode(AArch64::LDRXui);
3791 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
3792 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
3793 Ldr.addOperand(SymTLSDescLo12);
3795 EmitToStreamer(*OutStreamer, Ldr);
3796
3797 MCInst Add;
3798 Add.setOpcode(AArch64::ADDXri);
3799 Add.addOperand(MCOperand::createReg(AArch64::X0));
3800 Add.addOperand(MCOperand::createReg(AArch64::X0));
3801 Add.addOperand(SymTLSDescLo12);
3803 EmitToStreamer(*OutStreamer, Add);
3804
3805 // Emit a relocation-annotation. This expands to no code, but requests
3806 // the following instruction gets an R_AARCH64_AUTH_TLSDESC_CALL.
3807 MCInst TLSAuthDescCall;
3808 TLSAuthDescCall.setOpcode(AArch64::TLSAUTHDESCCALL);
3809 TLSAuthDescCall.addOperand(Sym);
3810 EmitToStreamer(*OutStreamer, TLSAuthDescCall);
3811#ifndef NDEBUG
3812 --InstsEmitted; // no code emitted
3813#endif
3814
3815 MCInst Blraa;
3816 Blraa.setOpcode(AArch64::BLRAA);
3817 Blraa.addOperand(MCOperand::createReg(AArch64::X16));
3818 Blraa.addOperand(MCOperand::createReg(AArch64::X0));
3819 EmitToStreamer(*OutStreamer, Blraa);
3820
3821 return;
3822 }
3823 case AArch64::TLSDESC_CALLSEQ: {
3824 /// lower this to:
3825 /// adrp x0, :tlsdesc:var
3826 /// ldr x1, [x0, #:tlsdesc_lo12:var]
3827 /// add x0, x0, #:tlsdesc_lo12:var
3828 /// .tlsdesccall var
3829 /// blr x1
3830 /// (TPIDR_EL0 offset now in x0)
3831 const MachineOperand &MO_Sym = MI->getOperand(0);
3832 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
3833 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
3834 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
3835 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
3836 MCInstLowering.lowerOperand(MO_Sym, Sym);
3837 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
3838 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
3839
3840 MCInst Adrp;
3841 Adrp.setOpcode(AArch64::ADRP);
3842 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
3843 Adrp.addOperand(SymTLSDesc);
3844 EmitToStreamer(*OutStreamer, Adrp);
3845
3846 MCInst Ldr;
3847 if (STI->isTargetILP32()) {
3848 Ldr.setOpcode(AArch64::LDRWui);
3849 Ldr.addOperand(MCOperand::createReg(AArch64::W1));
3850 } else {
3851 Ldr.setOpcode(AArch64::LDRXui);
3852 Ldr.addOperand(MCOperand::createReg(AArch64::X1));
3853 }
3854 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
3855 Ldr.addOperand(SymTLSDescLo12);
3857 EmitToStreamer(*OutStreamer, Ldr);
3858
3859 MCInst Add;
3860 if (STI->isTargetILP32()) {
3861 Add.setOpcode(AArch64::ADDWri);
3862 Add.addOperand(MCOperand::createReg(AArch64::W0));
3863 Add.addOperand(MCOperand::createReg(AArch64::W0));
3864 } else {
3865 Add.setOpcode(AArch64::ADDXri);
3866 Add.addOperand(MCOperand::createReg(AArch64::X0));
3867 Add.addOperand(MCOperand::createReg(AArch64::X0));
3868 }
3869 Add.addOperand(SymTLSDescLo12);
3871 EmitToStreamer(*OutStreamer, Add);
3872
3873 // Emit a relocation-annotation. This expands to no code, but requests
3874 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
3875 MCInst TLSDescCall;
3876 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
3877 TLSDescCall.addOperand(Sym);
3878 EmitToStreamer(*OutStreamer, TLSDescCall);
3879#ifndef NDEBUG
3880 --InstsEmitted; // no code emitted
3881#endif
3882
3883 MCInst Blr;
3884 Blr.setOpcode(AArch64::BLR);
3885 Blr.addOperand(MCOperand::createReg(AArch64::X1));
3886 EmitToStreamer(*OutStreamer, Blr);
3887
3888 return;
3889 }
3890
3891 case AArch64::JumpTableDest32:
3892 case AArch64::JumpTableDest16:
3893 case AArch64::JumpTableDest8:
3894 LowerJumpTableDest(*OutStreamer, *MI);
3895 return;
3896
3897 case AArch64::BR_JumpTable:
3898 LowerHardenedBRJumpTable(*MI);
3899 return;
3900
3901 case AArch64::FMOVH0:
3902 case AArch64::FMOVS0:
3903 case AArch64::FMOVD0:
3904 emitFMov0(*MI);
3905 return;
3906
3907 case AArch64::MOPSMemoryCopyPseudo:
3908 case AArch64::MOPSMemoryMovePseudo:
3909 case AArch64::MOPSMemorySetPseudo:
3910 case AArch64::MOPSMemorySetTaggingPseudo:
3911 LowerMOPS(*OutStreamer, *MI);
3912 return;
3913
3914 case TargetOpcode::STACKMAP:
3915 return LowerSTACKMAP(*OutStreamer, SM, *MI);
3916
3917 case TargetOpcode::PATCHPOINT:
3918 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
3919
3920 case TargetOpcode::STATEPOINT:
3921 return LowerSTATEPOINT(*OutStreamer, SM, *MI);
3922
3923 case TargetOpcode::FAULTING_OP:
3924 return LowerFAULTING_OP(*MI);
3925
3926 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
3927 LowerPATCHABLE_FUNCTION_ENTER(*MI);
3928 return;
3929
3930 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
3931 LowerPATCHABLE_FUNCTION_EXIT(*MI);
3932 return;
3933
3934 case TargetOpcode::PATCHABLE_TAIL_CALL:
3935 LowerPATCHABLE_TAIL_CALL(*MI);
3936 return;
3937 case TargetOpcode::PATCHABLE_EVENT_CALL:
3938 return LowerPATCHABLE_EVENT_CALL(*MI, false);
3939 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
3940 return LowerPATCHABLE_EVENT_CALL(*MI, true);
3941
3942 case AArch64::KCFI_CHECK:
3943 LowerKCFI_CHECK(*MI);
3944 return;
3945
3946 case AArch64::HWASAN_CHECK_MEMACCESS:
3947 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
3948 case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
3949 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
3950 LowerHWASAN_CHECK_MEMACCESS(*MI);
3951 return;
3952
3953 case AArch64::SEH_StackAlloc:
3954 TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
3955 return;
3956
3957 case AArch64::SEH_SaveFPLR:
3958 TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
3959 return;
3960
3961 case AArch64::SEH_SaveFPLR_X:
3962 assert(MI->getOperand(0).getImm() < 0 &&
3963 "Pre increment SEH opcode must have a negative offset");
3964 TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
3965 return;
3966
3967 case AArch64::SEH_SaveReg:
3968 TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
3969 MI->getOperand(1).getImm());
3970 return;
3971
3972 case AArch64::SEH_SaveReg_X:
3973 assert(MI->getOperand(1).getImm() < 0 &&
3974 "Pre increment SEH opcode must have a negative offset");
3975 TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
3976 -MI->getOperand(1).getImm());
3977 return;
3978
3979 case AArch64::SEH_SaveRegP:
3980 if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 &&
3981 MI->getOperand(0).getImm() <= 28) {
3982 assert((MI->getOperand(0).getImm() - 19) % 2 == 0 &&
3983 "Register paired with LR must be odd");
3984 TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(),
3985 MI->getOperand(2).getImm());
3986 return;
3987 }
3988 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
3989 "Non-consecutive registers not allowed for save_regp");
3990 TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
3991 MI->getOperand(2).getImm());
3992 return;
3993
3994 case AArch64::SEH_SaveRegP_X:
3995 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
3996 "Non-consecutive registers not allowed for save_regp_x");
3997 assert(MI->getOperand(2).getImm() < 0 &&
3998 "Pre increment SEH opcode must have a negative offset");
3999 TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
4000 -MI->getOperand(2).getImm());
4001 return;
4002
4003 case AArch64::SEH_SaveFReg:
4004 TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
4005 MI->getOperand(1).getImm());
4006 return;
4007
4008 case AArch64::SEH_SaveFReg_X:
4009 assert(MI->getOperand(1).getImm() < 0 &&
4010 "Pre increment SEH opcode must have a negative offset");
4011 TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
4012 -MI->getOperand(1).getImm());
4013 return;
4014
4015 case AArch64::SEH_SaveFRegP:
4016 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
4017 "Non-consecutive registers not allowed for save_regp");
4018 TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
4019 MI->getOperand(2).getImm());
4020 return;
4021
4022 case AArch64::SEH_SaveFRegP_X:
4023 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
4024 "Non-consecutive registers not allowed for save_regp_x");
4025 assert(MI->getOperand(2).getImm() < 0 &&
4026 "Pre increment SEH opcode must have a negative offset");
4027 TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
4028 -MI->getOperand(2).getImm());
4029 return;
4030
4031 case AArch64::SEH_SetFP:
4033 return;
4034
4035 case AArch64::SEH_AddFP:
4036 TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm());
4037 return;
4038
4039 case AArch64::SEH_Nop:
4040 TS->emitARM64WinCFINop();
4041 return;
4042
4043 case AArch64::SEH_PrologEnd:
4045 return;
4046
4047 case AArch64::SEH_EpilogStart:
4049 return;
4050
4051 case AArch64::SEH_EpilogEnd:
4053 return;
4054
4055 case AArch64::SEH_PACSignLR:
4057 return;
4058
4059 case AArch64::SEH_SaveAnyRegI:
4060 assert(MI->getOperand(1).getImm() <= 1008 &&
4061 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
4062 TS->emitARM64WinCFISaveAnyRegI(MI->getOperand(0).getImm(),
4063 MI->getOperand(1).getImm());
4064 return;
4065
4066 case AArch64::SEH_SaveAnyRegIP:
4067 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
4068 "Non-consecutive registers not allowed for save_any_reg");
4069 assert(MI->getOperand(2).getImm() <= 1008 &&
4070 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
4071 TS->emitARM64WinCFISaveAnyRegIP(MI->getOperand(0).getImm(),
4072 MI->getOperand(2).getImm());
4073 return;
4074
4075 case AArch64::SEH_SaveAnyRegQP:
4076 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
4077 "Non-consecutive registers not allowed for save_any_reg");
4078 assert(MI->getOperand(2).getImm() >= 0 &&
4079 "SaveAnyRegQP SEH opcode offset must be non-negative");
4080 assert(MI->getOperand(2).getImm() <= 1008 &&
4081 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
4082 TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(),
4083 MI->getOperand(2).getImm());
4084 return;
4085
4086 case AArch64::SEH_SaveAnyRegQPX:
4087 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
4088 "Non-consecutive registers not allowed for save_any_reg");
4089 assert(MI->getOperand(2).getImm() < 0 &&
4090 "SaveAnyRegQPX SEH opcode offset must be negative");
4091 assert(MI->getOperand(2).getImm() >= -1008 &&
4092 "SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
4093 TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(),
4094 -MI->getOperand(2).getImm());
4095 return;
4096
4097 case AArch64::SEH_AllocZ:
4098 assert(MI->getOperand(0).getImm() >= 0 &&
4099 "AllocZ SEH opcode offset must be non-negative");
4100 assert(MI->getOperand(0).getImm() <= 255 &&
4101 "AllocZ SEH opcode offset must fit into 8 bits");
4102 TS->emitARM64WinCFIAllocZ(MI->getOperand(0).getImm());
4103 return;
4104
4105 case AArch64::SEH_SaveZReg:
4106 assert(MI->getOperand(1).getImm() >= 0 &&
4107 "SaveZReg SEH opcode offset must be non-negative");
4108 assert(MI->getOperand(1).getImm() <= 255 &&
4109 "SaveZReg SEH opcode offset must fit into 8 bits");
4110 TS->emitARM64WinCFISaveZReg(MI->getOperand(0).getImm(),
4111 MI->getOperand(1).getImm());
4112 return;
4113
4114 case AArch64::SEH_SavePReg:
4115 assert(MI->getOperand(1).getImm() >= 0 &&
4116 "SavePReg SEH opcode offset must be non-negative");
4117 assert(MI->getOperand(1).getImm() <= 255 &&
4118 "SavePReg SEH opcode offset must fit into 8 bits");
4119 TS->emitARM64WinCFISavePReg(MI->getOperand(0).getImm(),
4120 MI->getOperand(1).getImm());
4121 return;
4122
4123 case AArch64::BLR:
4124 case AArch64::BR: {
4125 recordIfImportCall(MI);
4126 MCInst TmpInst;
4127 MCInstLowering.Lower(MI, TmpInst);
4128 EmitToStreamer(*OutStreamer, TmpInst);
4129 return;
4130 }
4131 case AArch64::CBWPri:
4132 case AArch64::CBXPri:
4133 case AArch64::CBBAssertExt:
4134 case AArch64::CBHAssertExt:
4135 case AArch64::CBWPrr:
4136 case AArch64::CBXPrr:
4137 emitCBPseudoExpansion(MI);
4138 return;
4139 case AArch64::ATOMIC_STORE_HINT_B:
4140 case AArch64::ATOMIC_STORE_HINT_H:
4141 case AArch64::ATOMIC_STORE_HINT_W:
4142 case AArch64::ATOMIC_STORE_HINT_X:
4143 emitAtomicHintPseudoExpansion(MI);
4144 return;
4145 case AArch64::ATOMIC_FETCH_HINT_W:
4146 case AArch64::ATOMIC_FETCH_HINT_X:
4147 emitAtomicFetchHintPseudoExpansion(MI);
4148 return;
4149 case AArch64::ATOMIC_STORE_HINT_BroW:
4150 case AArch64::ATOMIC_STORE_HINT_HroW:
4151 case AArch64::ATOMIC_STORE_HINT_WroW:
4152 case AArch64::ATOMIC_STORE_HINT_XroW:
4153 case AArch64::ATOMIC_STORE_HINT_SroW:
4154 case AArch64::ATOMIC_STORE_HINT_DroW:
4155 case AArch64::ATOMIC_STORE_HINT_BroX:
4156 case AArch64::ATOMIC_STORE_HINT_HroX:
4157 case AArch64::ATOMIC_STORE_HINT_WroX:
4158 case AArch64::ATOMIC_STORE_HINT_XroX:
4159 case AArch64::ATOMIC_STORE_HINT_SroX:
4160 case AArch64::ATOMIC_STORE_HINT_DroX:
4161 emitAtomicHintPseudoExpansionRO(MI);
4162 return;
4163 case AArch64::ATOMIC_STORE_HINT_Bui:
4164 case AArch64::ATOMIC_STORE_HINT_Hui:
4165 case AArch64::ATOMIC_STORE_HINT_Wui:
4166 case AArch64::ATOMIC_STORE_HINT_Xui:
4167 case AArch64::ATOMIC_STORE_HINT_Sui:
4168 case AArch64::ATOMIC_STORE_HINT_Dui:
4169 case AArch64::ATOMIC_STORE_HINT_Bi:
4170 case AArch64::ATOMIC_STORE_HINT_Hi:
4171 case AArch64::ATOMIC_STORE_HINT_Wi:
4172 case AArch64::ATOMIC_STORE_HINT_Xi:
4173 case AArch64::ATOMIC_STORE_HINT_Si:
4174 case AArch64::ATOMIC_STORE_HINT_Di:
4175 emitAtomicHintPseudoExpansionImm(MI);
4176 return;
4177 }
4178
4179 if (emitDeactivationSymbolRelocation(MI->getDeactivationSymbol()))
4180 return;
4181
4182 // Finally, do the automated lowerings for everything else.
4183 MCInst TmpInst;
4184 MCInstLowering.Lower(MI, TmpInst);
4185 EmitToStreamer(*OutStreamer, TmpInst);
4186}
4187
4188void AArch64AsmPrinter::recordIfImportCall(
4189 const llvm::MachineInstr *BranchInst) {
4190 if (!EnableImportCallOptimization)
4191 return;
4192
4193 auto [GV, OpFlags] = BranchInst->getMF()->tryGetCalledGlobal(BranchInst);
4194 if (GV && GV->hasDLLImportStorageClass()) {
4195 auto *CallSiteSymbol = MMI->getContext().createNamedTempSymbol("impcall");
4196 OutStreamer->emitLabel(CallSiteSymbol);
4197
4198 auto *CalledSymbol = MCInstLowering.GetGlobalValueSymbol(GV, OpFlags);
4199 SectionToImportedFunctionCalls[OutStreamer->getCurrentSectionOnly()]
4200 .push_back({CallSiteSymbol, CalledSymbol});
4201 }
4202}
4203
4204void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
4205 MCSymbol *LazyPointer) {
4206 // _ifunc:
4207 // adrp x16, lazy_pointer@GOTPAGE
4208 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
4209 // ldr x16, [x16]
4210 // br x16
4211
4212 {
4213 MCInst Adrp;
4214 Adrp.setOpcode(AArch64::ADRP);
4215 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
4216 MCOperand SymPage;
4217 MCInstLowering.lowerOperand(
4220 SymPage);
4221 Adrp.addOperand(SymPage);
4222 EmitToStreamer(Adrp);
4223 }
4224
4225 {
4226 MCInst Ldr;
4227 Ldr.setOpcode(AArch64::LDRXui);
4228 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
4229 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
4230 MCOperand SymPageOff;
4231 MCInstLowering.lowerOperand(
4234 SymPageOff);
4235 Ldr.addOperand(SymPageOff);
4237 EmitToStreamer(Ldr);
4238 }
4239
4240 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
4241 .addReg(AArch64::X16)
4242 .addReg(AArch64::X16)
4243 .addImm(0));
4244
4245 EmitToStreamer(MCInstBuilder(TM.getTargetTriple().isArm64e() ? AArch64::BRAAZ
4246 : AArch64::BR)
4247 .addReg(AArch64::X16));
4248}
4249
4250void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
4251 const GlobalIFunc &GI,
4252 MCSymbol *LazyPointer) {
4253 // These stub helpers are only ever called once, so here we're optimizing for
4254 // minimum size by using the pre-indexed store variants, which saves a few
4255 // bytes of instructions to bump & restore sp.
4256
4257 // _ifunc.stub_helper:
4258 // stp fp, lr, [sp, #-16]!
4259 // mov fp, sp
4260 // stp x1, x0, [sp, #-16]!
4261 // stp x3, x2, [sp, #-16]!
4262 // stp x5, x4, [sp, #-16]!
4263 // stp x7, x6, [sp, #-16]!
4264 // stp d1, d0, [sp, #-16]!
4265 // stp d3, d2, [sp, #-16]!
4266 // stp d5, d4, [sp, #-16]!
4267 // stp d7, d6, [sp, #-16]!
4268 // bl _resolver
4269 // adrp x16, lazy_pointer@GOTPAGE
4270 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
4271 // str x0, [x16]
4272 // mov x16, x0
4273 // ldp d7, d6, [sp], #16
4274 // ldp d5, d4, [sp], #16
4275 // ldp d3, d2, [sp], #16
4276 // ldp d1, d0, [sp], #16
4277 // ldp x7, x6, [sp], #16
4278 // ldp x5, x4, [sp], #16
4279 // ldp x3, x2, [sp], #16
4280 // ldp x1, x0, [sp], #16
4281 // ldp fp, lr, [sp], #16
4282 // br x16
4283
4284 EmitToStreamer(MCInstBuilder(AArch64::STPXpre)
4285 .addReg(AArch64::SP)
4286 .addReg(AArch64::FP)
4287 .addReg(AArch64::LR)
4288 .addReg(AArch64::SP)
4289 .addImm(-2));
4290
4291 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
4292 .addReg(AArch64::FP)
4293 .addReg(AArch64::SP)
4294 .addImm(0)
4295 .addImm(0));
4296
4297 for (int I = 0; I != 4; ++I)
4298 EmitToStreamer(MCInstBuilder(AArch64::STPXpre)
4299 .addReg(AArch64::SP)
4300 .addReg(AArch64::X1 + 2 * I)
4301 .addReg(AArch64::X0 + 2 * I)
4302 .addReg(AArch64::SP)
4303 .addImm(-2));
4304
4305 for (int I = 0; I != 4; ++I)
4306 EmitToStreamer(MCInstBuilder(AArch64::STPDpre)
4307 .addReg(AArch64::SP)
4308 .addReg(AArch64::D1 + 2 * I)
4309 .addReg(AArch64::D0 + 2 * I)
4310 .addReg(AArch64::SP)
4311 .addImm(-2));
4312
4313 EmitToStreamer(
4314 MCInstBuilder(AArch64::BL)
4316
4317 {
4318 MCInst Adrp;
4319 Adrp.setOpcode(AArch64::ADRP);
4320 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
4321 MCOperand SymPage;
4322 MCInstLowering.lowerOperand(
4323 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
4325 SymPage);
4326 Adrp.addOperand(SymPage);
4327 EmitToStreamer(Adrp);
4328 }
4329
4330 {
4331 MCInst Ldr;
4332 Ldr.setOpcode(AArch64::LDRXui);
4333 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
4334 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
4335 MCOperand SymPageOff;
4336 MCInstLowering.lowerOperand(
4337 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
4339 SymPageOff);
4340 Ldr.addOperand(SymPageOff);
4342 EmitToStreamer(Ldr);
4343 }
4344
4345 EmitToStreamer(MCInstBuilder(AArch64::STRXui)
4346 .addReg(AArch64::X0)
4347 .addReg(AArch64::X16)
4348 .addImm(0));
4349
4350 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
4351 .addReg(AArch64::X16)
4352 .addReg(AArch64::X0)
4353 .addImm(0)
4354 .addImm(0));
4355
4356 for (int I = 3; I != -1; --I)
4357 EmitToStreamer(MCInstBuilder(AArch64::LDPDpost)
4358 .addReg(AArch64::SP)
4359 .addReg(AArch64::D1 + 2 * I)
4360 .addReg(AArch64::D0 + 2 * I)
4361 .addReg(AArch64::SP)
4362 .addImm(2));
4363
4364 for (int I = 3; I != -1; --I)
4365 EmitToStreamer(MCInstBuilder(AArch64::LDPXpost)
4366 .addReg(AArch64::SP)
4367 .addReg(AArch64::X1 + 2 * I)
4368 .addReg(AArch64::X0 + 2 * I)
4369 .addReg(AArch64::SP)
4370 .addImm(2));
4371
4372 EmitToStreamer(MCInstBuilder(AArch64::LDPXpost)
4373 .addReg(AArch64::SP)
4374 .addReg(AArch64::FP)
4375 .addReg(AArch64::LR)
4376 .addReg(AArch64::SP)
4377 .addImm(2));
4378
4379 EmitToStreamer(MCInstBuilder(TM.getTargetTriple().isArm64e() ? AArch64::BRAAZ
4380 : AArch64::BR)
4381 .addReg(AArch64::X16));
4382}
4383
4384const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV,
4385 const Constant *BaseCV,
4386 uint64_t Offset) {
4387 if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
4388 return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0),
4389 OutContext);
4390 }
4391
4392 return AsmPrinter::lowerConstant(CV, BaseCV, Offset);
4393}
4394
4395char AArch64AsmPrinter::ID = 0;
4396
4397INITIALIZE_PASS(AArch64AsmPrinter, "aarch64-asm-printer",
4398 "AArch64 Assembly Printer", false, false)
4399
4400// Force static initialization.
4401extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
4402LLVMInitializeAArch64AsmPrinter() {
4408}
4409
4412 AArch64AsmPrinter &AsmPrinter = static_cast<AArch64AsmPrinter &>(
4413 MAM.getResult<AsmPrinterAnalysis>(M).getPrinter());
4416 return PreservedAnalyses::all();
4417}
4418
4422 AArch64AsmPrinter &AsmPrinter = static_cast<AArch64AsmPrinter &>(
4424 .getCachedResult<AsmPrinterAnalysis>(*MF.getFunction().getParent())
4425 ->getPrinter());
4428 return PreservedAnalyses::all();
4429}
4430
4433 AArch64AsmPrinter &AsmPrinter = static_cast<AArch64AsmPrinter &>(
4434 MAM.getResult<AsmPrinterAnalysis>(M).getPrinter());
4437 return PreservedAnalyses::all();
4438}
#define GET_CB_OPC(IsImm, Width, ImmCond, RegCond)
static void emitAuthenticatedPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel, const MCExpr *StubAuthPtrRef)
static bool getOptionalBooleanModuleFlag(Module &M, StringRef Name)
static bool targetSupportsIRelativeRelocation(const Triple &TT)
static PtrauthCheckMode getCheckMode(const MachineFunction *MF)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
print mir2vec MIR2Vec Vocabulary Printer Pass
Definition MIR2Vec.cpp:629
Machine Check Debug Module
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define P(N)
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:484
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
This file defines the SmallString class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
std::unique_ptr< MCStreamer > && Streamer
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool printAsmMRegister(const X86AsmPrinter &P, const MachineInstr &MI, const MachineOperand &MO, char Mode, raw_ostream &O)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
static const AArch64AuthMCExpr * create(const MCExpr *Expr, uint16_t Discriminator, AArch64PACKey::ID Key, bool HasAddressDiversity, MCContext &Ctx, SMLoc Loc=SMLoc())
const SetOfInstructions & getLOHRelated() const
unsigned getJumpTableEntrySize(int Idx) const
MCSymbol * getJumpTableEntryPCRelSymbol(int Idx) const
static bool shouldSignReturnAddress(SignReturnAddress Condition, bool IsLRSpilled)
std::optional< std::string > getOutliningStyle() const
const MILOHContainer & getLOHContainer() const
void setJumpTableEntryInfo(int Idx, unsigned Size, MCSymbol *PCRelSym)
static const char * getRegisterName(MCRegister Reg, unsigned AltIdx=AArch64::NoRegAltName)
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
AArch64MCInstLower - This class is used to lower an MachineInstr into an MCInst.
MCSymbol * GetGlobalValueSymbol(const GlobalValue *GV, unsigned TargetFlags) const
void Lower(const MachineInstr *MI, MCInst &OutMI) const
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
const AArch64Options & getCLOpts() const
virtual void emitARM64WinCFISaveRegP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveRegPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegQP(unsigned Reg, int Offset)
virtual void emitAttributesSubsection(StringRef VendorName, AArch64BuildAttributes::SubsectionOptional IsOptional, AArch64BuildAttributes::SubsectionType ParameterType)
Build attributes implementation.
virtual void emitARM64WinCFISavePReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegI(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFRegPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveRegX(unsigned Reg, int Offset)
virtual void emitARM64WinCFIAllocStack(unsigned Size)
virtual void emitARM64WinCFISaveFPLRX(int Offset)
virtual void emitARM64WinCFIAllocZ(int Offset)
virtual void emitDirectiveVariantPCS(MCSymbol *Symbol)
Callback used to implement the .variant_pcs directive.
virtual void emitARM64WinCFIAddFP(unsigned Size)
virtual void emitARM64WinCFISaveFPLR(int Offset)
virtual void emitARM64WinCFISaveFRegP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFRegX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveZReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveLRPair(unsigned Reg, int Offset)
virtual void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value, std::string String)
virtual void emitARM64WinCFISaveAnyRegIP(unsigned Reg, int Offset)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
void setPreservesAll()
Set by analyses that do not transform their input at all.
const T & front() const
Get the first element.
Definition ArrayRef.h:144
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:95
virtual void emitGlobalAlias(const Module &M, const GlobalAlias &GA)
virtual MCSymbol * GetCPISymbol(unsigned CPID) const
Return the symbol for the specified constant pool entry.
virtual const MCExpr * lowerConstant(const Constant *CV, const Constant *BaseCV=nullptr, uint64_t Offset=0)
Lower the specified LLVM Constant to an MCExpr.
bool doInitialization(Module &M) override
Set up the AsmPrinter when we are working on a new module.
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
bool doFinalization(Module &M) override
Shut down the asmprinter.
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition AsmPrinter.h:466
virtual void emitXXStructor(const DataLayout &DL, const Constant *CV)
Targets can override this to change how global constants that are part of a C++ static/global constru...
Definition AsmPrinter.h:671
virtual void emitFunctionEntryLabel()
EmitFunctionEntryLabel - Emit the label that is the entrypoint for the function.
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
virtual const MCExpr * lowerBlockAddressConstant(const BlockAddress &BA)
Lower the specified BlockAddress to an MCExpr.
Function * getFunction() const
Definition Constants.h:1126
static LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:168
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Constant * getPointer() const
The pointer that is signed in this ptrauth signed pointer.
Definition Constants.h:1251
static LLVM_ABI ConstantPtrAuth * get(Constant *Ptr, ConstantInt *Key, ConstantInt *Disc, Constant *AddrDisc, Constant *DeactivationSymbol)
Return a pointer signed with the specified parameters.
ConstantInt * getKey() const
The Key ID, an i32 constant.
Definition Constants.h:1254
Constant * getDeactivationSymbol() const
Definition Constants.h:1273
bool hasAddressDiscriminator() const
Whether there is any non-null address discriminator.
Definition Constants.h:1269
ConstantInt * getDiscriminator() const
The integer discriminator, an i64 constant, or 0.
Definition Constants.h:1257
LLVM_ABI void recordFaultingOp(FaultKind FaultTy, const MCSymbol *FaultingLabel, const MCSymbol *HandlerLabel)
Definition FaultMaps.cpp:28
LLVM_ABI void serializeToFaultMapSection()
Definition FaultMaps.cpp:45
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:273
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:734
const Constant * getAliasee() const
Definition GlobalAlias.h:87
const Constant * getResolver() const
Definition GlobalIFunc.h:73
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this GlobalObject.
bool hasLocalLinkage() const
bool hasExternalWeakLinkage() const
Type * getValueType() const
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
static const MCBinaryExpr * createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:422
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:342
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:427
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
MCSectionELF * getELFSection(const Twine &Section, unsigned Type, unsigned Flags)
Definition MCContext.h:550
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
LLVM_ABI MCSymbol * createLinkerPrivateSymbol(const Twine &Name)
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
LLVM_ABI bool evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm) const
Try to evaluate the expression to a relocatable value, i.e.
Definition MCExpr.cpp:450
void setFlags(unsigned F)
Definition MCInst.h:204
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
MCSection * getDataSection() const
void setImm(int64_t Val)
Definition MCInst.h:89
static MCOperand createExpr(const MCExpr *Val)
Definition MCInst.h:166
int64_t getImm() const
Definition MCInst.h:84
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
bool isReg() const
Definition MCInst.h:65
MCRegister getRegister(unsigned i) const
getRegister - Return the specified register in the class.
uint16_t getEncodingValue(MCRegister Reg) const
Returns the encoding for Reg.
static constexpr unsigned NonUniqueID
Definition MCSection.h:585
static const MCSpecifierExpr * create(const MCExpr *Expr, Spec S, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.cpp:743
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual void emitCFIBKeyFrame()
virtual bool popSection()
Restore the current and previous section from the section stack.
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual void emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc={})
Record a relocation described by the .reloc directive.
virtual bool hasRawTextSupport() const
Return true if this asm streamer supports emitting unformatted text to the .s file with EmitRawText.
Definition MCStreamer.h:385
MCContext & getContext() const
Definition MCStreamer.h:326
virtual void AddComment(const Twine &T, bool EOL=true)
Add a textual comment.
Definition MCStreamer.h:404
virtual void emitCFIMTETaggedFrame()
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
MCTargetStreamer * getTargetStreamer()
Definition MCStreamer.h:336
void pushSection()
Save the current and previous section on the section stack.
Definition MCStreamer.h:460
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
MCSection * getCurrentSectionOnly() const
Definition MCStreamer.h:438
void emitRawText(const Twine &String)
If this file is backed by a assembly streamer, this dumps the specified string in the output ....
const FeatureBitset & getFeatureBits() const
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:213
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:59
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
const MCSymbol * getAddSym() const
Definition MCValue.h:49
int64_t getConstant() const
Definition MCValue.h:44
MachineInstrBundleIterator< const MachineInstr > const_iterator
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
CalledGlobalInfo tryGetCalledGlobal(const MachineInstr *MI) const
Tries to get the global and target flags for a call site, if the instruction is a call to a global.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MCContext & getContext() const
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineBasicBlock & front() const
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
mop_range operands()
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
const std::vector< MachineJumpTableEntry > & getJumpTables() const
unsigned getSubReg() const
static MachineOperand CreateMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
const GlobalValue * getGlobal() const
static MachineOperand CreateES(const char *SymName, unsigned TargetFlags=0)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
const BlockAddress * getBlockAddress() const
void setOffset(int64_t Offset)
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
int64_t getOffset() const
Return the offset from the symbol in this operand.
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
Root of the metadata hierarchy.
Definition Metadata.h:64
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
static SectionKind getMetadata()
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void push_back(const T &Elt)
LLVM_ABI void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
LLVM_ABI void recordPatchPoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a patchpoint instruction.
LLVM_ABI void recordStackMap(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a stackmap instruction.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr const char * data() const
Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:138
virtual MCSection * getSectionForJumpTable(const Function &F, const TargetMachine &TM) const
Primary interface to the complete machine description for the target machine.
bool regsOverlap(Register RegA, Register RegB) const
Returns true if the two registers are equal or alias each other.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
bool isFunctionTy() const
True if this is an instance of FunctionType.
Definition Type.h:268
LLVM Value Representation.
Definition Value.h:75
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI StringRef getVendorName(unsigned const Vendor)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_S
MO_S - Indicates that the bits of the symbol operand represented by MO_G0 etc are signed.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
PtrauthCheckMode
Ways to check pointer authentication auth/resign failures.
constexpr AArch64PACKey::ID InitFiniKey
PAuth key to be used with function pointers in .init_array and .fini_array.
AuthCheckMethod
Variants of check performed on an authenticated pointer.
constexpr unsigned InitFiniPointerConstantDiscriminator
Constant discriminator to be used with function pointers in .init_array and .fini_array.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ SectionSize
Definition COFF.h:61
SymbolStorageClass
Storage class tells where and what the symbol represents.
Definition COFF.h:218
@ IMAGE_SYM_CLASS_EXTERNAL
External symbol.
Definition COFF.h:224
@ IMAGE_SYM_CLASS_STATIC
Static.
Definition COFF.h:225
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
Definition COFF.h:276
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
Definition COFF.h:280
@ AARCH64_PAUTH_PLATFORM_LLVM_LINUX
Definition ELF.h:1886
@ SHF_ALLOC
Definition ELF.h:1259
@ SHF_GROUP
Definition ELF.h:1281
@ SHF_EXECINSTR
Definition ELF.h:1262
@ GNU_PROPERTY_AARCH64_FEATURE_1_BTI
Definition ELF.h:1877
@ GNU_PROPERTY_AARCH64_FEATURE_1_PAC
Definition ELF.h:1878
@ GNU_PROPERTY_AARCH64_FEATURE_1_GCS
Definition ELF.h:1879
@ SHT_PROGBITS
Definition ELF.h:1157
@ S_REGULAR
S_REGULAR - Regular section.
Definition MachO.h:127
void emitInstruction(MCObjectStreamer &, const MCInst &Inst, const MCSubtargetInfo &STI)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract_or_null(Y &&MD)
Extract a Value from Metadata, allowing null.
Definition Metadata.h:694
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
Definition Metadata.h:679
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
bool empty() const
Definition BasicBlock.h:101
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
LLVM_ABI std::optional< std::string > getArm64ECMangledFunctionName(StringRef Name)
Returns the ARM64EC mangled function name unless the input is already mangled.
Definition Mangler.cpp:292
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
OuterAnalysisManagerProxy< ModuleAnalysisManager, MachineFunction > ModuleAnalysisManagerMachineFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
scope_exit(Callable) -> scope_exit< Callable >
@ Store
The extracted value is stored (ExtractElement only).
static unsigned getXPACOpcodeForKey(AArch64PACKey::ID K)
Return XPAC opcode to be used for a ptrauth strip using the given key.
Target & getTheAArch64beTarget()
std::string utostr(uint64_t X, bool isNeg=false)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
static unsigned getBranchOpcodeForKey(bool IsCall, AArch64PACKey::ID K, bool Zero)
Return B(L)RA opcode to be used for an authenticated branch or call using the given key,...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
Target & getTheAArch64leTarget()
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
Target & getTheAArch64_32Target()
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI void setupModuleAsmPrinter(Module &M, ModuleAnalysisManager &MAM, AsmPrinter &AsmPrinter)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Target & getTheARM64_32Target()
static MCRegister getXRegFromWReg(MCRegister Reg)
@ Add
Sum of integers.
Target & getTheARM64Target()
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
static MCRegister getXRegFromXRegTuple(MCRegister RegTuple)
static unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero)
Return PAC opcode to be used for a ptrauth sign using the given key, or its PAC*Z variant that doesn'...
static MCRegister getWRegFromXReg(MCRegister Reg)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
ExceptionHandling
Definition CodeGen.h:54
LLVM_ABI void setupMachineFunctionAsmPrinter(MachineFunctionAnalysisManager &MFAM, MachineFunction &MF, AsmPrinter &AsmPrinter)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
static unsigned getAUTOpcodeForKey(AArch64PACKey::ID K, bool Zero)
Return AUT opcode to be used for a ptrauth auth using the given key, or its AUT*Z variant that doesn'...
@ MCSA_Weak
.weak
@ MCSA_WeakAntiDep
.weak_anti_dep (COFF)
@ MCSA_ELF_TypeFunction
.type _foo, STT_FUNC # aka @function
@ MCSA_Hidden
.hidden (ELF)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define EQ(a, b)
Definition regexec.c:65
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...