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