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