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