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