LLVM 19.0.0git
AArch64AsmPrinter.cpp
Go to the documentation of this file.
1//===- AArch64AsmPrinter.cpp - AArch64 LLVM assembly writer ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to the AArch64 assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AArch64.h"
15#include "AArch64MCInstLower.h"
17#include "AArch64RegisterInfo.h"
18#include "AArch64Subtarget.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/ADT/Twine.h"
44#include "llvm/IR/DataLayout.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"
53#include "llvm/MC/MCStreamer.h"
54#include "llvm/MC/MCSymbol.h"
63#include <algorithm>
64#include <cassert>
65#include <cstdint>
66#include <map>
67#include <memory>
68
69using namespace llvm;
70
71#define DEBUG_TYPE "asm-printer"
72
73namespace {
74
75class AArch64AsmPrinter : public AsmPrinter {
76 AArch64MCInstLower MCInstLowering;
77 FaultMaps FM;
78 const AArch64Subtarget *STI;
79 bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false;
80
81public:
82 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
83 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
84 FM(*this) {}
85
86 StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
87
88 /// Wrapper for MCInstLowering.lowerOperand() for the
89 /// tblgen'erated pseudo lowering.
90 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
91 return MCInstLowering.lowerOperand(MO, MCOp);
92 }
93
94 const MCExpr *lowerConstantPtrAuth(const ConstantPtrAuth &CPA) override;
95
96 void emitStartOfAsmFile(Module &M) override;
97 void emitJumpTableInfo() override;
98 std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
100 getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
101 const MCSymbol *BranchLabel) const override;
102
103 void emitFunctionEntryLabel() override;
104
105 void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
106
107 void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI);
108
109 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
110 const MachineInstr &MI);
111 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
112 const MachineInstr &MI);
113 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
114 const MachineInstr &MI);
115 void LowerFAULTING_OP(const MachineInstr &MI);
116
117 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
118 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
119 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
120 void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
121
122 typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
123 HwasanMemaccessTuple;
124 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
125 void LowerKCFI_CHECK(const MachineInstr &MI);
126 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
127 void emitHwasanMemaccessSymbols(Module &M);
128
129 void emitSled(const MachineInstr &MI, SledKind Kind);
130
131 // Emit the sequence for BLRA (authenticate + branch).
132 void emitPtrauthBranch(const MachineInstr *MI);
133 // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc.
134 unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc,
135 unsigned &InstsEmitted);
136
137 // Emit the sequence for LOADauthptrstatic
138 void LowerLOADauthptrstatic(const MachineInstr &MI);
139
140 // Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or
141 // adrp-add followed by PAC sign)
142 void LowerMOVaddrPAC(const MachineInstr &MI);
143
144 /// tblgen'erated driver function for lowering simple MI->MC
145 /// pseudo instructions.
146 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
147 const MachineInstr *MI);
148
149 void emitInstruction(const MachineInstr *MI) override;
150
151 void emitFunctionHeaderComment() override;
152
153 void getAnalysisUsage(AnalysisUsage &AU) const override {
155 AU.setPreservesAll();
156 }
157
158 bool runOnMachineFunction(MachineFunction &MF) override {
159 AArch64FI = MF.getInfo<AArch64FunctionInfo>();
160 STI = &MF.getSubtarget<AArch64Subtarget>();
161
163
164 if (STI->isTargetCOFF()) {
165 bool Local = MF.getFunction().hasLocalLinkage();
168 int Type =
170
171 OutStreamer->beginCOFFSymbolDef(CurrentFnSym);
172 OutStreamer->emitCOFFSymbolStorageClass(Scl);
173 OutStreamer->emitCOFFSymbolType(Type);
174 OutStreamer->endCOFFSymbolDef();
175 }
176
177 // Emit the rest of the function body.
179
180 // Emit the XRay table for this function.
182
183 // We didn't modify anything.
184 return false;
185 }
186
187 const MCExpr *lowerConstant(const Constant *CV) override;
188
189private:
190 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
191 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
192 bool printAsmRegInClass(const MachineOperand &MO,
193 const TargetRegisterClass *RC, unsigned AltName,
194 raw_ostream &O);
195
196 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
197 const char *ExtraCode, raw_ostream &O) override;
198 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
199 const char *ExtraCode, raw_ostream &O) override;
200
201 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
202
203 void emitFunctionBodyEnd() override;
204
205 MCSymbol *GetCPISymbol(unsigned CPID) const override;
206 void emitEndOfAsmFile(Module &M) override;
207
208 AArch64FunctionInfo *AArch64FI = nullptr;
209
210 /// Emit the LOHs contained in AArch64FI.
211 void emitLOHs();
212
213 /// Emit instruction to set float register to zero.
214 void emitFMov0(const MachineInstr &MI);
215
216 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
217
218 MInstToMCSymbol LOHInstToLabel;
219
221 return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
222 }
223
224 const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
225 assert(STI);
226 return STI;
227 }
228 void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
229 MCSymbol *LazyPointer) override;
231 MCSymbol *LazyPointer) override;
232};
233
234} // end anonymous namespace
235
236void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
237 const Triple &TT = TM.getTargetTriple();
238
239 if (TT.isOSBinFormatCOFF()) {
240 // Emit an absolute @feat.00 symbol
241 MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00"));
242 OutStreamer->beginCOFFSymbolDef(S);
243 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
244 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL);
245 OutStreamer->endCOFFSymbolDef();
246 int64_t Feat00Value = 0;
247
248 if (M.getModuleFlag("cfguard")) {
249 // Object is CFG-aware.
250 Feat00Value |= COFF::Feat00Flags::GuardCF;
251 }
252
253 if (M.getModuleFlag("ehcontguard")) {
254 // Object also has EHCont.
255 Feat00Value |= COFF::Feat00Flags::GuardEHCont;
256 }
257
258 if (M.getModuleFlag("ms-kernel")) {
259 // Object is compiled with /kernel.
260 Feat00Value |= COFF::Feat00Flags::Kernel;
261 }
262
263 OutStreamer->emitSymbolAttribute(S, MCSA_Global);
264 OutStreamer->emitAssignment(
265 S, MCConstantExpr::create(Feat00Value, MMI->getContext()));
266 }
267
268 if (!TT.isOSBinFormatELF())
269 return;
270
271 // Assemble feature flags that may require creation of a note section.
272 unsigned Flags = 0;
273 if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
274 M.getModuleFlag("branch-target-enforcement")))
275 if (!BTE->isZero())
277
278 if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
279 M.getModuleFlag("guarded-control-stack")))
280 if (!GCS->isZero())
282
283 if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
284 M.getModuleFlag("sign-return-address")))
285 if (!Sign->isZero())
287
288 uint64_t PAuthABIPlatform = -1;
289 if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
290 M.getModuleFlag("aarch64-elf-pauthabi-platform")))
291 PAuthABIPlatform = PAP->getZExtValue();
292 uint64_t PAuthABIVersion = -1;
293 if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
294 M.getModuleFlag("aarch64-elf-pauthabi-version")))
295 PAuthABIVersion = PAV->getZExtValue();
296
297 // Emit a .note.gnu.property section with the flags.
298 auto *TS =
299 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
300 TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion);
301}
302
303void AArch64AsmPrinter::emitFunctionHeaderComment() {
304 const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>();
305 std::optional<std::string> OutlinerString = FI->getOutliningStyle();
306 if (OutlinerString != std::nullopt)
307 OutStreamer->getCommentOS() << ' ' << OutlinerString;
308}
309
310void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
311{
312 const Function &F = MF->getFunction();
313 if (F.hasFnAttribute("patchable-function-entry")) {
314 unsigned Num;
315 if (F.getFnAttribute("patchable-function-entry")
316 .getValueAsString()
317 .getAsInteger(10, Num))
318 return;
319 emitNops(Num);
320 return;
321 }
322
323 emitSled(MI, SledKind::FUNCTION_ENTER);
324}
325
326void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
327 emitSled(MI, SledKind::FUNCTION_EXIT);
328}
329
330void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
331 emitSled(MI, SledKind::TAIL_CALL);
332}
333
334void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
335 static const int8_t NoopsInSledCount = 7;
336 // We want to emit the following pattern:
337 //
338 // .Lxray_sled_N:
339 // ALIGN
340 // B #32
341 // ; 7 NOP instructions (28 bytes)
342 // .tmpN
343 //
344 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
345 // over the full 32 bytes (8 instructions) with the following pattern:
346 //
347 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
348 // LDR W17, #12 ; W17 := function ID
349 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
350 // BLR X16 ; call the tracing trampoline
351 // ;DATA: 32 bits of function ID
352 // ;DATA: lower 32 bits of the address of the trampoline
353 // ;DATA: higher 32 bits of the address of the trampoline
354 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
355 //
356 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
357 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
358 OutStreamer->emitLabel(CurSled);
359 auto Target = OutContext.createTempSymbol();
360
361 // Emit "B #32" instruction, which jumps over the next 28 bytes.
362 // The operand has to be the number of 4-byte instructions to jump over,
363 // including the current instruction.
364 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
365
366 for (int8_t I = 0; I < NoopsInSledCount; I++)
367 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
368
369 OutStreamer->emitLabel(Target);
370 recordSled(CurSled, MI, Kind, 2);
371}
372
373// Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
374// (built-in functions __xray_customevent/__xray_typedevent).
375//
376// .Lxray_event_sled_N:
377// b 1f
378// save x0 and x1 (and also x2 for TYPED_EVENT_CALL)
379// set up x0 and x1 (and also x2 for TYPED_EVENT_CALL)
380// bl __xray_CustomEvent or __xray_TypedEvent
381// restore x0 and x1 (and also x2 for TYPED_EVENT_CALL)
382// 1:
383//
384// There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL.
385//
386// Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT.
387// After patching, b .+N will become a nop.
388void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
389 bool Typed) {
390 auto &O = *OutStreamer;
391 MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
392 O.emitLabel(CurSled);
393 MCInst MovX0Op0 = MCInstBuilder(AArch64::ORRXrs)
394 .addReg(AArch64::X0)
395 .addReg(AArch64::XZR)
396 .addReg(MI.getOperand(0).getReg())
397 .addImm(0);
398 MCInst MovX1Op1 = MCInstBuilder(AArch64::ORRXrs)
399 .addReg(AArch64::X1)
400 .addReg(AArch64::XZR)
401 .addReg(MI.getOperand(1).getReg())
402 .addImm(0);
403 bool MachO = TM.getTargetTriple().isOSBinFormatMachO();
405 OutContext.getOrCreateSymbol(
406 Twine(MachO ? "_" : "") +
407 (Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")),
408 OutContext);
409 if (Typed) {
410 O.AddComment("Begin XRay typed event");
411 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9));
412 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
413 .addReg(AArch64::SP)
414 .addReg(AArch64::X0)
415 .addReg(AArch64::X1)
416 .addReg(AArch64::SP)
417 .addImm(-4));
418 EmitToStreamer(O, MCInstBuilder(AArch64::STRXui)
419 .addReg(AArch64::X2)
420 .addReg(AArch64::SP)
421 .addImm(2));
422 EmitToStreamer(O, MovX0Op0);
423 EmitToStreamer(O, MovX1Op1);
424 EmitToStreamer(O, MCInstBuilder(AArch64::ORRXrs)
425 .addReg(AArch64::X2)
426 .addReg(AArch64::XZR)
427 .addReg(MI.getOperand(2).getReg())
428 .addImm(0));
429 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
430 EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui)
431 .addReg(AArch64::X2)
432 .addReg(AArch64::SP)
433 .addImm(2));
434 O.AddComment("End XRay typed event");
435 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
436 .addReg(AArch64::SP)
437 .addReg(AArch64::X0)
438 .addReg(AArch64::X1)
439 .addReg(AArch64::SP)
440 .addImm(4));
441
442 recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2);
443 } else {
444 O.AddComment("Begin XRay custom event");
445 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6));
446 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
447 .addReg(AArch64::SP)
448 .addReg(AArch64::X0)
449 .addReg(AArch64::X1)
450 .addReg(AArch64::SP)
451 .addImm(-2));
452 EmitToStreamer(O, MovX0Op0);
453 EmitToStreamer(O, MovX1Op1);
454 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
455 O.AddComment("End XRay custom event");
456 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
457 .addReg(AArch64::SP)
458 .addReg(AArch64::X0)
459 .addReg(AArch64::X1)
460 .addReg(AArch64::SP)
461 .addImm(2));
462
463 recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2);
464 }
465}
466
467void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
468 Register AddrReg = MI.getOperand(0).getReg();
469 assert(std::next(MI.getIterator())->isCall() &&
470 "KCFI_CHECK not followed by a call instruction");
471 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
472 "KCFI_CHECK call target doesn't match call operand");
473
474 // Default to using the intra-procedure-call temporary registers for
475 // comparing the hashes.
476 unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
477 if (AddrReg == AArch64::XZR) {
478 // Checking XZR makes no sense. Instead of emitting a load, zero
479 // ScratchRegs[0] and use it for the ESR AddrIndex below.
480 AddrReg = getXRegFromWReg(ScratchRegs[0]);
481 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
482 .addReg(AddrReg)
483 .addReg(AArch64::XZR)
484 .addReg(AArch64::XZR)
485 .addImm(0));
486 } else {
487 // If one of the scratch registers is used for the call target (e.g.
488 // with AArch64::TCRETURNriBTI), we can clobber another caller-saved
489 // temporary register instead (in this case, AArch64::W9) as the check
490 // is immediately followed by the call instruction.
491 for (auto &Reg : ScratchRegs) {
492 if (Reg == getWRegFromXReg(AddrReg)) {
493 Reg = AArch64::W9;
494 break;
495 }
496 }
497 assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
498 "Invalid scratch registers for KCFI_CHECK");
499
500 // Adjust the offset for patchable-function-prefix. This assumes that
501 // patchable-function-prefix is the same for all functions.
502 int64_t PrefixNops = 0;
503 (void)MI.getMF()
504 ->getFunction()
505 .getFnAttribute("patchable-function-prefix")
506 .getValueAsString()
507 .getAsInteger(10, PrefixNops);
508
509 // Load the target function type hash.
510 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
511 .addReg(ScratchRegs[0])
512 .addReg(AddrReg)
513 .addImm(-(PrefixNops * 4 + 4)));
514 }
515
516 // Load the expected type hash.
517 const int64_t Type = MI.getOperand(1).getImm();
518 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
519 .addReg(ScratchRegs[1])
520 .addReg(ScratchRegs[1])
521 .addImm(Type & 0xFFFF)
522 .addImm(0));
523 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
524 .addReg(ScratchRegs[1])
525 .addReg(ScratchRegs[1])
526 .addImm((Type >> 16) & 0xFFFF)
527 .addImm(16));
528
529 // Compare the hashes and trap if there's a mismatch.
530 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs)
531 .addReg(AArch64::WZR)
532 .addReg(ScratchRegs[0])
533 .addReg(ScratchRegs[1])
534 .addImm(0));
535
536 MCSymbol *Pass = OutContext.createTempSymbol();
537 EmitToStreamer(*OutStreamer,
538 MCInstBuilder(AArch64::Bcc)
539 .addImm(AArch64CC::EQ)
540 .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
541
542 // The base ESR is 0x8000 and the register information is encoded in bits
543 // 0-9 as follows:
544 // - 0-4: n, where the register Xn contains the target address
545 // - 5-9: m, where the register Wm contains the expected type hash
546 // Where n, m are in [0, 30].
547 unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
548 unsigned AddrIndex;
549 switch (AddrReg) {
550 default:
551 AddrIndex = AddrReg - AArch64::X0;
552 break;
553 case AArch64::FP:
554 AddrIndex = 29;
555 break;
556 case AArch64::LR:
557 AddrIndex = 30;
558 break;
559 }
560
561 assert(AddrIndex < 31 && TypeIndex < 31);
562
563 unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
564 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR));
565 OutStreamer->emitLabel(Pass);
566}
567
568void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
569 Register Reg = MI.getOperand(0).getReg();
570 bool IsShort =
571 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
572 (MI.getOpcode() ==
573 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
574 uint32_t AccessInfo = MI.getOperand(1).getImm();
575 bool IsFixedShadow =
576 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
577 (MI.getOpcode() ==
578 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
579 uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0;
580
581 MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
582 Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
583 if (!Sym) {
584 // FIXME: Make this work on non-ELF.
585 if (!TM.getTargetTriple().isOSBinFormatELF())
586 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
587
588 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
589 utostr(AccessInfo);
590 if (IsFixedShadow)
591 SymName += "_fixed_" + utostr(FixedShadowOffset);
592 if (IsShort)
593 SymName += "_short_v2";
594 Sym = OutContext.getOrCreateSymbol(SymName);
595 }
596
597 EmitToStreamer(*OutStreamer,
598 MCInstBuilder(AArch64::BL)
599 .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
600}
601
602void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
603 if (HwasanMemaccessSymbols.empty())
604 return;
605
606 const Triple &TT = TM.getTargetTriple();
607 assert(TT.isOSBinFormatELF());
608 std::unique_ptr<MCSubtargetInfo> STI(
609 TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
610 assert(STI && "Unable to create subtarget info");
611
612 MCSymbol *HwasanTagMismatchV1Sym =
613 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
614 MCSymbol *HwasanTagMismatchV2Sym =
615 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
616
617 const MCSymbolRefExpr *HwasanTagMismatchV1Ref =
618 MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext);
619 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
620 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
621
622 for (auto &P : HwasanMemaccessSymbols) {
623 unsigned Reg = std::get<0>(P.first);
624 bool IsShort = std::get<1>(P.first);
625 uint32_t AccessInfo = std::get<2>(P.first);
626 bool IsFixedShadow = std::get<3>(P.first);
627 uint64_t FixedShadowOffset = std::get<4>(P.first);
628 const MCSymbolRefExpr *HwasanTagMismatchRef =
629 IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
630 MCSymbol *Sym = P.second;
631
632 bool HasMatchAllTag =
633 (AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1;
634 uint8_t MatchAllTag =
635 (AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff;
636 unsigned Size =
637 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
638 bool CompileKernel =
639 (AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1;
640
641 OutStreamer->switchSection(OutContext.getELFSection(
642 ".text.hot", ELF::SHT_PROGBITS,
644 /*IsComdat=*/true));
645
646 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
647 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
648 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
649 OutStreamer->emitLabel(Sym);
650
651 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SBFMXri)
652 .addReg(AArch64::X16)
653 .addReg(Reg)
654 .addImm(4)
655 .addImm(55),
656 *STI);
657
658 if (IsFixedShadow) {
659 // Aarch64 makes it difficult to embed large constants in the code.
660 // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit
661 // left-shift option in the MOV instruction. Combined with the 16-bit
662 // immediate, this is enough to represent any offset up to 2**48.
663 OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
664 .addReg(AArch64::X17)
665 .addImm(FixedShadowOffset >> 32)
666 .addImm(32),
667 *STI);
668 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX)
669 .addReg(AArch64::W16)
670 .addReg(AArch64::X17)
671 .addReg(AArch64::X16)
672 .addImm(0)
673 .addImm(0),
674 *STI);
675 } else {
676 OutStreamer->emitInstruction(
677 MCInstBuilder(AArch64::LDRBBroX)
678 .addReg(AArch64::W16)
679 .addReg(IsShort ? AArch64::X20 : AArch64::X9)
680 .addReg(AArch64::X16)
681 .addImm(0)
682 .addImm(0),
683 *STI);
684 }
685
686 OutStreamer->emitInstruction(
687 MCInstBuilder(AArch64::SUBSXrs)
688 .addReg(AArch64::XZR)
689 .addReg(AArch64::X16)
690 .addReg(Reg)
692 *STI);
693 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
694 OutStreamer->emitInstruction(
695 MCInstBuilder(AArch64::Bcc)
697 .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
698 OutContext)),
699 *STI);
700 MCSymbol *ReturnSym = OutContext.createTempSymbol();
701 OutStreamer->emitLabel(ReturnSym);
702 OutStreamer->emitInstruction(
703 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
704 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
705
706 if (HasMatchAllTag) {
707 OutStreamer->emitInstruction(MCInstBuilder(AArch64::UBFMXri)
708 .addReg(AArch64::X17)
709 .addReg(Reg)
710 .addImm(56)
711 .addImm(63),
712 *STI);
713 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSXri)
714 .addReg(AArch64::XZR)
715 .addReg(AArch64::X17)
716 .addImm(MatchAllTag)
717 .addImm(0),
718 *STI);
719 OutStreamer->emitInstruction(
720 MCInstBuilder(AArch64::Bcc)
722 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
723 *STI);
724 }
725
726 if (IsShort) {
727 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWri)
728 .addReg(AArch64::WZR)
729 .addReg(AArch64::W16)
730 .addImm(15)
731 .addImm(0),
732 *STI);
733 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
734 OutStreamer->emitInstruction(
735 MCInstBuilder(AArch64::Bcc)
737 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
738 *STI);
739
740 OutStreamer->emitInstruction(
741 MCInstBuilder(AArch64::ANDXri)
742 .addReg(AArch64::X17)
743 .addReg(Reg)
745 *STI);
746 if (Size != 1)
747 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
748 .addReg(AArch64::X17)
749 .addReg(AArch64::X17)
750 .addImm(Size - 1)
751 .addImm(0),
752 *STI);
753 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWrs)
754 .addReg(AArch64::WZR)
755 .addReg(AArch64::W16)
756 .addReg(AArch64::W17)
757 .addImm(0),
758 *STI);
759 OutStreamer->emitInstruction(
760 MCInstBuilder(AArch64::Bcc)
762 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
763 *STI);
764
765 OutStreamer->emitInstruction(
766 MCInstBuilder(AArch64::ORRXri)
767 .addReg(AArch64::X16)
768 .addReg(Reg)
770 *STI);
771 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBui)
772 .addReg(AArch64::W16)
773 .addReg(AArch64::X16)
774 .addImm(0),
775 *STI);
776 OutStreamer->emitInstruction(
777 MCInstBuilder(AArch64::SUBSXrs)
778 .addReg(AArch64::XZR)
779 .addReg(AArch64::X16)
780 .addReg(Reg)
782 *STI);
783 OutStreamer->emitInstruction(
784 MCInstBuilder(AArch64::Bcc)
786 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
787 *STI);
788
789 OutStreamer->emitLabel(HandleMismatchSym);
790 }
791
792 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
793 .addReg(AArch64::SP)
794 .addReg(AArch64::X0)
795 .addReg(AArch64::X1)
796 .addReg(AArch64::SP)
797 .addImm(-32),
798 *STI);
799 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
800 .addReg(AArch64::FP)
801 .addReg(AArch64::LR)
802 .addReg(AArch64::SP)
803 .addImm(29),
804 *STI);
805
806 if (Reg != AArch64::X0)
807 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ORRXrs)
808 .addReg(AArch64::X0)
809 .addReg(AArch64::XZR)
810 .addReg(Reg)
811 .addImm(0),
812 *STI);
813 OutStreamer->emitInstruction(
814 MCInstBuilder(AArch64::MOVZXi)
815 .addReg(AArch64::X1)
817 .addImm(0),
818 *STI);
819
820 if (CompileKernel) {
821 // The Linux kernel's dynamic loader doesn't support GOT relative
822 // relocations, but it doesn't support late binding either, so just call
823 // the function directly.
824 OutStreamer->emitInstruction(
825 MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef), *STI);
826 } else {
827 // Intentionally load the GOT entry and branch to it, rather than possibly
828 // late binding the function, which may clobber the registers before we
829 // have a chance to save them.
830 OutStreamer->emitInstruction(
831 MCInstBuilder(AArch64::ADRP)
832 .addReg(AArch64::X16)
834 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_PAGE,
835 OutContext)),
836 *STI);
837 OutStreamer->emitInstruction(
838 MCInstBuilder(AArch64::LDRXui)
839 .addReg(AArch64::X16)
840 .addReg(AArch64::X16)
842 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_LO12,
843 OutContext)),
844 *STI);
845 OutStreamer->emitInstruction(
846 MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI);
847 }
848 }
849}
850
851static void emitAuthenticatedPointer(MCStreamer &OutStreamer,
852 MCSymbol *StubLabel,
853 const MCExpr *StubAuthPtrRef) {
854 // sym$auth_ptr$key$disc:
855 OutStreamer.emitLabel(StubLabel);
856 OutStreamer.emitValue(StubAuthPtrRef, /*size=*/8);
857}
858
859void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
860 emitHwasanMemaccessSymbols(M);
861
862 const Triple &TT = TM.getTargetTriple();
863 if (TT.isOSBinFormatMachO()) {
864 // Output authenticated pointers as indirect symbols, if we have any.
865 MachineModuleInfoMachO &MMIMacho =
866 MMI->getObjFileInfo<MachineModuleInfoMachO>();
867
868 auto Stubs = MMIMacho.getAuthGVStubList();
869
870 if (!Stubs.empty()) {
871 // Switch to the "__auth_ptr" section.
872 OutStreamer->switchSection(
873 OutContext.getMachOSection("__DATA", "__auth_ptr", MachO::S_REGULAR,
875 emitAlignment(Align(8));
876
877 for (const auto &Stub : Stubs)
878 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
879
880 OutStreamer->addBlankLine();
881 }
882
883 // Funny Darwin hack: This flag tells the linker that no global symbols
884 // contain code that falls through to other global symbols (e.g. the obvious
885 // implementation of multiple entry points). If this doesn't occur, the
886 // linker can safely perform dead code stripping. Since LLVM never
887 // generates code that does this, it is always safe to set.
888 OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols);
889 }
890
891 if (TT.isOSBinFormatELF()) {
892 // Output authenticated pointers as indirect symbols, if we have any.
893 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
894
895 auto Stubs = MMIELF.getAuthGVStubList();
896
897 if (!Stubs.empty()) {
898 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
899 OutStreamer->switchSection(TLOF.getDataSection());
900 emitAlignment(Align(8));
901
902 for (const auto &Stub : Stubs)
903 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
904
905 OutStreamer->addBlankLine();
906 }
907 }
908
909 // Emit stack and fault map information.
910 FM.serializeToFaultMapSection();
911
912}
913
914void AArch64AsmPrinter::emitLOHs() {
916
917 for (const auto &D : AArch64FI->getLOHContainer()) {
918 for (const MachineInstr *MI : D.getArgs()) {
919 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
920 assert(LabelIt != LOHInstToLabel.end() &&
921 "Label hasn't been inserted for LOH related instruction");
922 MCArgs.push_back(LabelIt->second);
923 }
924 OutStreamer->emitLOHDirective(D.getKind(), MCArgs);
925 MCArgs.clear();
926 }
927}
928
929void AArch64AsmPrinter::emitFunctionBodyEnd() {
930 if (!AArch64FI->getLOHRelated().empty())
931 emitLOHs();
932}
933
934/// GetCPISymbol - Return the symbol for the specified constant pool entry.
935MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
936 // Darwin uses a linker-private symbol name for constant-pools (to
937 // avoid addends on the relocation?), ELF has no such concept and
938 // uses a normal private symbol.
939 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
940 return OutContext.getOrCreateSymbol(
941 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
942 Twine(getFunctionNumber()) + "_" + Twine(CPID));
943
944 return AsmPrinter::GetCPISymbol(CPID);
945}
946
947void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
948 raw_ostream &O) {
949 const MachineOperand &MO = MI->getOperand(OpNum);
950 switch (MO.getType()) {
951 default:
952 llvm_unreachable("<unknown operand type>");
954 Register Reg = MO.getReg();
955 assert(Reg.isPhysical());
956 assert(!MO.getSubReg() && "Subregs should be eliminated!");
958 break;
959 }
961 O << MO.getImm();
962 break;
963 }
965 PrintSymbolOperand(MO, O);
966 break;
967 }
969 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
970 Sym->print(O, MAI);
971 break;
972 }
973 }
974}
975
976bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
977 raw_ostream &O) {
978 Register Reg = MO.getReg();
979 switch (Mode) {
980 default:
981 return true; // Unknown mode.
982 case 'w':
983 Reg = getWRegFromXReg(Reg);
984 break;
985 case 'x':
986 Reg = getXRegFromWReg(Reg);
987 break;
988 case 't':
990 break;
991 }
992
994 return false;
995}
996
997// Prints the register in MO using class RC using the offset in the
998// new register class. This should not be used for cross class
999// printing.
1000bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
1001 const TargetRegisterClass *RC,
1002 unsigned AltName, raw_ostream &O) {
1003 assert(MO.isReg() && "Should only get here with a register!");
1004 const TargetRegisterInfo *RI = STI->getRegisterInfo();
1005 Register Reg = MO.getReg();
1006 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
1007 if (!RI->regsOverlap(RegToPrint, Reg))
1008 return true;
1009 O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName);
1010 return false;
1011}
1012
1013bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
1014 const char *ExtraCode, raw_ostream &O) {
1015 const MachineOperand &MO = MI->getOperand(OpNum);
1016
1017 // First try the generic code, which knows about modifiers like 'c' and 'n'.
1018 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
1019 return false;
1020
1021 // Does this asm operand have a single letter operand modifier?
1022 if (ExtraCode && ExtraCode[0]) {
1023 if (ExtraCode[1] != 0)
1024 return true; // Unknown modifier.
1025
1026 switch (ExtraCode[0]) {
1027 default:
1028 return true; // Unknown modifier.
1029 case 'w': // Print W register
1030 case 'x': // Print X register
1031 if (MO.isReg())
1032 return printAsmMRegister(MO, ExtraCode[0], O);
1033 if (MO.isImm() && MO.getImm() == 0) {
1034 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
1036 return false;
1037 }
1038 printOperand(MI, OpNum, O);
1039 return false;
1040 case 'b': // Print B register.
1041 case 'h': // Print H register.
1042 case 's': // Print S register.
1043 case 'd': // Print D register.
1044 case 'q': // Print Q register.
1045 case 'z': // Print Z register.
1046 if (MO.isReg()) {
1047 const TargetRegisterClass *RC;
1048 switch (ExtraCode[0]) {
1049 case 'b':
1050 RC = &AArch64::FPR8RegClass;
1051 break;
1052 case 'h':
1053 RC = &AArch64::FPR16RegClass;
1054 break;
1055 case 's':
1056 RC = &AArch64::FPR32RegClass;
1057 break;
1058 case 'd':
1059 RC = &AArch64::FPR64RegClass;
1060 break;
1061 case 'q':
1062 RC = &AArch64::FPR128RegClass;
1063 break;
1064 case 'z':
1065 RC = &AArch64::ZPRRegClass;
1066 break;
1067 default:
1068 return true;
1069 }
1070 return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
1071 }
1072 printOperand(MI, OpNum, O);
1073 return false;
1074 }
1075 }
1076
1077 // According to ARM, we should emit x and v registers unless we have a
1078 // modifier.
1079 if (MO.isReg()) {
1080 Register Reg = MO.getReg();
1081
1082 // If this is a w or x register, print an x register.
1083 if (AArch64::GPR32allRegClass.contains(Reg) ||
1084 AArch64::GPR64allRegClass.contains(Reg))
1085 return printAsmMRegister(MO, 'x', O);
1086
1087 // If this is an x register tuple, print an x register.
1088 if (AArch64::GPR64x8ClassRegClass.contains(Reg))
1089 return printAsmMRegister(MO, 't', O);
1090
1091 unsigned AltName = AArch64::NoRegAltName;
1092 const TargetRegisterClass *RegClass;
1093 if (AArch64::ZPRRegClass.contains(Reg)) {
1094 RegClass = &AArch64::ZPRRegClass;
1095 } else if (AArch64::PPRRegClass.contains(Reg)) {
1096 RegClass = &AArch64::PPRRegClass;
1097 } else if (AArch64::PNRRegClass.contains(Reg)) {
1098 RegClass = &AArch64::PNRRegClass;
1099 } else {
1100 RegClass = &AArch64::FPR128RegClass;
1101 AltName = AArch64::vreg;
1102 }
1103
1104 // If this is a b, h, s, d, or q register, print it as a v register.
1105 return printAsmRegInClass(MO, RegClass, AltName, O);
1106 }
1107
1108 printOperand(MI, OpNum, O);
1109 return false;
1110}
1111
1112bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1113 unsigned OpNum,
1114 const char *ExtraCode,
1115 raw_ostream &O) {
1116 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
1117 return true; // Unknown modifier.
1118
1119 const MachineOperand &MO = MI->getOperand(OpNum);
1120 assert(MO.isReg() && "unexpected inline asm memory operand");
1121 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
1122 return false;
1123}
1124
1125void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
1126 raw_ostream &OS) {
1127 unsigned NOps = MI->getNumOperands();
1128 assert(NOps == 4);
1129 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
1130 // cast away const; DIetc do not take const operands for some reason.
1131 OS << MI->getDebugVariable()->getName();
1132 OS << " <- ";
1133 // Frame address. Currently handles register +- offset only.
1134 assert(MI->isIndirectDebugValue());
1135 OS << '[';
1136 for (unsigned I = 0, E = std::distance(MI->debug_operands().begin(),
1137 MI->debug_operands().end());
1138 I < E; ++I) {
1139 if (I != 0)
1140 OS << ", ";
1141 printOperand(MI, I, OS);
1142 }
1143 OS << ']';
1144 OS << "+";
1145 printOperand(MI, NOps - 2, OS);
1146}
1147
1148void AArch64AsmPrinter::emitJumpTableInfo() {
1149 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
1150 if (!MJTI) return;
1151
1152 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
1153 if (JT.empty()) return;
1154
1155 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1156 MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(MF->getFunction(), TM);
1157 OutStreamer->switchSection(ReadOnlySec);
1158
1159 auto AFI = MF->getInfo<AArch64FunctionInfo>();
1160 for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
1161 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
1162
1163 // If this jump table was deleted, ignore it.
1164 if (JTBBs.empty()) continue;
1165
1166 unsigned Size = AFI->getJumpTableEntrySize(JTI);
1167 emitAlignment(Align(Size));
1168 OutStreamer->emitLabel(GetJTISymbol(JTI));
1169
1170 const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1171 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
1172
1173 for (auto *JTBB : JTBBs) {
1174 const MCExpr *Value =
1175 MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext);
1176
1177 // Each entry is:
1178 // .byte/.hword (LBB - Lbase)>>2
1179 // or plain:
1180 // .word LBB - Lbase
1181 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
1182 if (Size != 4)
1184 Value, MCConstantExpr::create(2, OutContext), OutContext);
1185
1186 OutStreamer->emitValue(Value, Size);
1187 }
1188 }
1189}
1190
1191std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
1193AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI,
1194 const MachineInstr *BranchInstr,
1195 const MCSymbol *BranchLabel) const {
1196 const auto AFI = MF->getInfo<AArch64FunctionInfo>();
1197 const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1199 switch (AFI->getJumpTableEntrySize(JTI)) {
1200 case 1:
1201 EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
1202 break;
1203 case 2:
1204 EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
1205 break;
1206 case 4:
1207 EntrySize = codeview::JumpTableEntrySize::Int32;
1208 break;
1209 default:
1210 llvm_unreachable("Unexpected jump table entry size");
1211 }
1212 return std::make_tuple(Base, 0, BranchLabel, EntrySize);
1213}
1214
1215void AArch64AsmPrinter::emitFunctionEntryLabel() {
1216 if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
1217 MF->getFunction().getCallingConv() ==
1219 MF->getInfo<AArch64FunctionInfo>()->isSVECC()) {
1220 auto *TS =
1221 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1222 TS->emitDirectiveVariantPCS(CurrentFnSym);
1223 }
1224
1226
1227 if (TM.getTargetTriple().isWindowsArm64EC() &&
1228 !MF->getFunction().hasLocalLinkage()) {
1229 // For ARM64EC targets, a function definition's name is mangled differently
1230 // from the normal symbol, emit required aliases here.
1231 auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) {
1232 OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep);
1233 OutStreamer->emitAssignment(
1235 MMI->getContext()));
1236 };
1237
1238 auto getSymbolFromMetadata = [&](StringRef Name) {
1239 MCSymbol *Sym = nullptr;
1240 if (MDNode *Node = MF->getFunction().getMetadata(Name)) {
1241 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1242 Sym = MMI->getContext().getOrCreateSymbol(NameStr);
1243 }
1244 return Sym;
1245 };
1246
1247 if (MCSymbol *UnmangledSym =
1248 getSymbolFromMetadata("arm64ec_unmangled_name")) {
1249 MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name");
1250
1251 if (ECMangledSym) {
1252 // An external function, emit the alias from the unmangled symbol to
1253 // mangled symbol name and the alias from the mangled symbol to guest
1254 // exit thunk.
1255 emitFunctionAlias(UnmangledSym, ECMangledSym);
1256 emitFunctionAlias(ECMangledSym, CurrentFnSym);
1257 } else {
1258 // A function implementation, emit the alias from the unmangled symbol
1259 // to mangled symbol name.
1260 emitFunctionAlias(UnmangledSym, CurrentFnSym);
1261 }
1262 }
1263 }
1264}
1265
1266/// Small jump tables contain an unsigned byte or half, representing the offset
1267/// from the lowest-addressed possible destination to the desired basic
1268/// block. Since all instructions are 4-byte aligned, this is further compressed
1269/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
1270/// materialize the correct destination we need:
1271///
1272/// adr xDest, .LBB0_0
1273/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
1274/// add xDest, xDest, xScratch (with "lsl #2" for smaller entries)
1275void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer,
1276 const llvm::MachineInstr &MI) {
1277 Register DestReg = MI.getOperand(0).getReg();
1278 Register ScratchReg = MI.getOperand(1).getReg();
1279 Register ScratchRegW =
1280 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
1281 Register TableReg = MI.getOperand(2).getReg();
1282 Register EntryReg = MI.getOperand(3).getReg();
1283 int JTIdx = MI.getOperand(4).getIndex();
1284 int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
1285
1286 // This has to be first because the compression pass based its reachability
1287 // calculations on the start of the JumpTableDest instruction.
1288 auto Label =
1289 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
1290
1291 // If we don't already have a symbol to use as the base, use the ADR
1292 // instruction itself.
1293 if (!Label) {
1294 Label = MF->getContext().createTempSymbol();
1295 AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label);
1296 OutStreamer.emitLabel(Label);
1297 }
1298
1299 auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext());
1300 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
1301 .addReg(DestReg)
1302 .addExpr(LabelExpr));
1303
1304 // Load the number of instruction-steps to offset from the label.
1305 unsigned LdrOpcode;
1306 switch (Size) {
1307 case 1: LdrOpcode = AArch64::LDRBBroX; break;
1308 case 2: LdrOpcode = AArch64::LDRHHroX; break;
1309 case 4: LdrOpcode = AArch64::LDRSWroX; break;
1310 default:
1311 llvm_unreachable("Unknown jump table size");
1312 }
1313
1314 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
1315 .addReg(Size == 4 ? ScratchReg : ScratchRegW)
1316 .addReg(TableReg)
1317 .addReg(EntryReg)
1318 .addImm(0)
1319 .addImm(Size == 1 ? 0 : 1));
1320
1321 // Add to the already materialized base label address, multiplying by 4 if
1322 // compressed.
1323 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1324 .addReg(DestReg)
1325 .addReg(DestReg)
1326 .addReg(ScratchReg)
1327 .addImm(Size == 4 ? 0 : 2));
1328}
1329
1330void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer,
1331 const llvm::MachineInstr &MI) {
1332 unsigned Opcode = MI.getOpcode();
1333 assert(STI->hasMOPS());
1334 assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
1335
1336 const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
1337 if (Opcode == AArch64::MOPSMemoryCopyPseudo)
1338 return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
1339 if (Opcode == AArch64::MOPSMemoryMovePseudo)
1340 return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
1341 if (Opcode == AArch64::MOPSMemorySetPseudo)
1342 return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
1343 if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
1344 return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
1345 llvm_unreachable("Unhandled memory operation pseudo");
1346 }();
1347 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
1348 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
1349
1350 for (auto Op : Ops) {
1351 int i = 0;
1352 auto MCIB = MCInstBuilder(Op);
1353 // Destination registers
1354 MCIB.addReg(MI.getOperand(i++).getReg());
1355 MCIB.addReg(MI.getOperand(i++).getReg());
1356 if (!IsSet)
1357 MCIB.addReg(MI.getOperand(i++).getReg());
1358 // Input registers
1359 MCIB.addReg(MI.getOperand(i++).getReg());
1360 MCIB.addReg(MI.getOperand(i++).getReg());
1361 MCIB.addReg(MI.getOperand(i++).getReg());
1362
1363 EmitToStreamer(OutStreamer, MCIB);
1364 }
1365}
1366
1367void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1368 const MachineInstr &MI) {
1369 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
1370
1371 auto &Ctx = OutStreamer.getContext();
1372 MCSymbol *MILabel = Ctx.createTempSymbol();
1373 OutStreamer.emitLabel(MILabel);
1374
1375 SM.recordStackMap(*MILabel, MI);
1376 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1377
1378 // Scan ahead to trim the shadow.
1379 const MachineBasicBlock &MBB = *MI.getParent();
1381 ++MII;
1382 while (NumNOPBytes > 0) {
1383 if (MII == MBB.end() || MII->isCall() ||
1384 MII->getOpcode() == AArch64::DBG_VALUE ||
1385 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1386 MII->getOpcode() == TargetOpcode::STACKMAP)
1387 break;
1388 ++MII;
1389 NumNOPBytes -= 4;
1390 }
1391
1392 // Emit nops.
1393 for (unsigned i = 0; i < NumNOPBytes; i += 4)
1394 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1395}
1396
1397// Lower a patchpoint of the form:
1398// [<def>], <id>, <numBytes>, <target>, <numArgs>
1399void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1400 const MachineInstr &MI) {
1401 auto &Ctx = OutStreamer.getContext();
1402 MCSymbol *MILabel = Ctx.createTempSymbol();
1403 OutStreamer.emitLabel(MILabel);
1404 SM.recordPatchPoint(*MILabel, MI);
1405
1406 PatchPointOpers Opers(&MI);
1407
1408 int64_t CallTarget = Opers.getCallTarget().getImm();
1409 unsigned EncodedBytes = 0;
1410 if (CallTarget) {
1411 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
1412 "High 16 bits of call target should be zero.");
1413 Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
1414 EncodedBytes = 16;
1415 // Materialize the jump address:
1416 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1417 .addReg(ScratchReg)
1418 .addImm((CallTarget >> 32) & 0xFFFF)
1419 .addImm(32));
1420 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1421 .addReg(ScratchReg)
1422 .addReg(ScratchReg)
1423 .addImm((CallTarget >> 16) & 0xFFFF)
1424 .addImm(16));
1425 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1426 .addReg(ScratchReg)
1427 .addReg(ScratchReg)
1428 .addImm(CallTarget & 0xFFFF)
1429 .addImm(0));
1430 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
1431 }
1432 // Emit padding.
1433 unsigned NumBytes = Opers.getNumPatchBytes();
1434 assert(NumBytes >= EncodedBytes &&
1435 "Patchpoint can't request size less than the length of a call.");
1436 assert((NumBytes - EncodedBytes) % 4 == 0 &&
1437 "Invalid number of NOP bytes requested!");
1438 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
1439 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1440}
1441
1442void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1443 const MachineInstr &MI) {
1444 StatepointOpers SOpers(&MI);
1445 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1446 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1447 for (unsigned i = 0; i < PatchBytes; i += 4)
1448 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1449 } else {
1450 // Lower call target and choose correct opcode
1451 const MachineOperand &CallTarget = SOpers.getCallTarget();
1452 MCOperand CallTargetMCOp;
1453 unsigned CallOpcode;
1454 switch (CallTarget.getType()) {
1457 MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1458 CallOpcode = AArch64::BL;
1459 break;
1461 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
1462 CallOpcode = AArch64::BL;
1463 break;
1465 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
1466 CallOpcode = AArch64::BLR;
1467 break;
1468 default:
1469 llvm_unreachable("Unsupported operand type in statepoint call target");
1470 break;
1471 }
1472
1473 EmitToStreamer(OutStreamer,
1474 MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
1475 }
1476
1477 auto &Ctx = OutStreamer.getContext();
1478 MCSymbol *MILabel = Ctx.createTempSymbol();
1479 OutStreamer.emitLabel(MILabel);
1480 SM.recordStatepoint(*MILabel, MI);
1481}
1482
1483void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) {
1484 // FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>,
1485 // <opcode>, <operands>
1486
1487 Register DefRegister = FaultingMI.getOperand(0).getReg();
1489 static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm());
1490 MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol();
1491 unsigned Opcode = FaultingMI.getOperand(3).getImm();
1492 unsigned OperandsBeginIdx = 4;
1493
1494 auto &Ctx = OutStreamer->getContext();
1495 MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1496 OutStreamer->emitLabel(FaultingLabel);
1497
1498 assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!");
1499 FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1500
1501 MCInst MI;
1502 MI.setOpcode(Opcode);
1503
1504 if (DefRegister != (Register)0)
1505 MI.addOperand(MCOperand::createReg(DefRegister));
1506
1507 for (const MachineOperand &MO :
1508 llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) {
1509 MCOperand Dest;
1510 lowerOperand(MO, Dest);
1511 MI.addOperand(Dest);
1512 }
1513
1514 OutStreamer->AddComment("on-fault: " + HandlerLabel->getName());
1515 OutStreamer->emitInstruction(MI, getSubtargetInfo());
1516}
1517
1518void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
1519 Register DestReg = MI.getOperand(0).getReg();
1520 if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() &&
1521 STI->isNeonAvailable()) {
1522 // Convert H/S register to corresponding D register
1523 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
1524 DestReg = AArch64::D0 + (DestReg - AArch64::H0);
1525 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
1526 DestReg = AArch64::D0 + (DestReg - AArch64::S0);
1527 else
1528 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
1529
1530 MCInst MOVI;
1531 MOVI.setOpcode(AArch64::MOVID);
1532 MOVI.addOperand(MCOperand::createReg(DestReg));
1533 MOVI.addOperand(MCOperand::createImm(0));
1534 EmitToStreamer(*OutStreamer, MOVI);
1535 } else {
1536 MCInst FMov;
1537 switch (MI.getOpcode()) {
1538 default: llvm_unreachable("Unexpected opcode");
1539 case AArch64::FMOVH0:
1540 FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
1541 if (!STI->hasFullFP16())
1542 DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
1543 FMov.addOperand(MCOperand::createReg(DestReg));
1544 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
1545 break;
1546 case AArch64::FMOVS0:
1547 FMov.setOpcode(AArch64::FMOVWSr);
1548 FMov.addOperand(MCOperand::createReg(DestReg));
1549 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
1550 break;
1551 case AArch64::FMOVD0:
1552 FMov.setOpcode(AArch64::FMOVXDr);
1553 FMov.addOperand(MCOperand::createReg(DestReg));
1554 FMov.addOperand(MCOperand::createReg(AArch64::XZR));
1555 break;
1556 }
1557 EmitToStreamer(*OutStreamer, FMov);
1558 }
1559}
1560
1561unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
1562 unsigned AddrDisc,
1563 unsigned &InstsEmitted) {
1564 // So far we've used NoRegister in pseudos. Now we need real encodings.
1565 if (AddrDisc == AArch64::NoRegister)
1566 AddrDisc = AArch64::XZR;
1567
1568 // If there is no constant discriminator, there's no blend involved:
1569 // just use the address discriminator register as-is (XZR or not).
1570 if (!Disc)
1571 return AddrDisc;
1572
1573 // If there's only a constant discriminator, MOV it into x17.
1574 if (AddrDisc == AArch64::XZR) {
1575 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1576 .addReg(AArch64::X17)
1577 .addImm(Disc)
1578 .addImm(/*shift=*/0));
1579 ++InstsEmitted;
1580 return AArch64::X17;
1581 }
1582
1583 // If there are both, emit a blend into x17.
1584 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1585 .addReg(AArch64::X17)
1586 .addReg(AArch64::XZR)
1587 .addReg(AddrDisc)
1588 .addImm(0));
1589 ++InstsEmitted;
1590 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1591 .addReg(AArch64::X17)
1592 .addReg(AArch64::X17)
1593 .addImm(Disc)
1594 .addImm(/*shift=*/48));
1595 ++InstsEmitted;
1596 return AArch64::X17;
1597}
1598
1599void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
1600 unsigned InstsEmitted = 0;
1601 unsigned BrTarget = MI->getOperand(0).getReg();
1602
1603 auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm();
1604 assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
1605 "Invalid auth call key");
1606
1607 uint64_t Disc = MI->getOperand(2).getImm();
1608 assert(isUInt<16>(Disc));
1609
1610 unsigned AddrDisc = MI->getOperand(3).getReg();
1611
1612 // Compute discriminator into x17
1613 unsigned DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, InstsEmitted);
1614 bool IsZeroDisc = DiscReg == AArch64::XZR;
1615
1616 unsigned Opc;
1617 if (Key == AArch64PACKey::IA)
1618 Opc = IsZeroDisc ? AArch64::BLRAAZ : AArch64::BLRAA;
1619 else
1620 Opc = IsZeroDisc ? AArch64::BLRABZ : AArch64::BLRAB;
1621
1622 MCInst BRInst;
1623 BRInst.setOpcode(Opc);
1624 BRInst.addOperand(MCOperand::createReg(BrTarget));
1625 if (!IsZeroDisc)
1626 BRInst.addOperand(MCOperand::createReg(DiscReg));
1627 EmitToStreamer(*OutStreamer, BRInst);
1628 ++InstsEmitted;
1629
1630 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
1631}
1632
1633const MCExpr *
1634AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
1635 MCContext &Ctx = OutContext;
1636
1637 // Figure out the base symbol and the addend, if any.
1638 APInt Offset(64, 0);
1639 const Value *BaseGV = CPA.getPointer()->stripAndAccumulateConstantOffsets(
1640 getDataLayout(), Offset, /*AllowNonInbounds=*/true);
1641
1642 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
1643
1644 // If we can't understand the referenced ConstantExpr, there's nothing
1645 // else we can do: emit an error.
1646 if (!BaseGVB) {
1647 BaseGV->getContext().emitError(
1648 "cannot resolve target base/addend of ptrauth constant");
1649 return nullptr;
1650 }
1651
1652 // If there is an addend, turn that into the appropriate MCExpr.
1653 const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
1654 if (Offset.sgt(0))
1656 Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
1657 else if (Offset.slt(0))
1659 Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
1660
1661 uint64_t KeyID = CPA.getKey()->getZExtValue();
1662 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
1663 // AArch64AuthMCExpr::printImpl, so fail fast.
1664 if (KeyID > AArch64PACKey::LAST)
1665 report_fatal_error("AArch64 PAC Key ID '" + Twine(KeyID) +
1666 "' out of range [0, " +
1667 Twine((unsigned)AArch64PACKey::LAST) + "]");
1668
1669 uint64_t Disc = CPA.getDiscriminator()->getZExtValue();
1670 if (!isUInt<16>(Disc))
1671 report_fatal_error("AArch64 PAC Discriminator '" + Twine(Disc) +
1672 "' out of range [0, 0xFFFF]");
1673
1674 // Finally build the complete @AUTH expr.
1675 return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
1676 CPA.hasAddressDiscriminator(), Ctx);
1677}
1678
1679void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
1680 unsigned DstReg = MI.getOperand(0).getReg();
1681 const MachineOperand &GAOp = MI.getOperand(1);
1682 const uint64_t KeyC = MI.getOperand(2).getImm();
1683 assert(KeyC <= AArch64PACKey::LAST &&
1684 "key is out of range [0, AArch64PACKey::LAST]");
1685 const auto Key = (AArch64PACKey::ID)KeyC;
1686 const uint64_t Disc = MI.getOperand(3).getImm();
1687 assert(isUInt<16>(Disc) &&
1688 "constant discriminator is out of range [0, 0xffff]");
1689
1690 // Emit instruction sequence like the following:
1691 // ADRP x16, symbol$auth_ptr$key$disc
1692 // LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc]
1693 //
1694 // Where the $auth_ptr$ symbol is the stub slot containing the signed pointer
1695 // to symbol.
1696 MCSymbol *AuthPtrStubSym;
1697 if (TM.getTargetTriple().isOSBinFormatELF()) {
1698 const auto &TLOF =
1699 static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering());
1700
1701 assert(GAOp.getOffset() == 0 &&
1702 "non-zero offset for $auth_ptr$ stub slots is not supported");
1703 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
1704 AuthPtrStubSym =
1705 TLOF.getAuthPtrSlotSymbol(TM, &MF->getMMI(), GASym, Key, Disc);
1706 } else {
1707 assert(TM.getTargetTriple().isOSBinFormatMachO() &&
1708 "LOADauthptrstatic is implemented only for MachO/ELF");
1709
1710 const auto &TLOF = static_cast<const AArch64_MachoTargetObjectFile &>(
1711 getObjFileLowering());
1712
1713 assert(GAOp.getOffset() == 0 &&
1714 "non-zero offset for $auth_ptr$ stub slots is not supported");
1715 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
1716 AuthPtrStubSym =
1717 TLOF.getAuthPtrSlotSymbol(TM, &MF->getMMI(), GASym, Key, Disc);
1718 }
1719
1720 MachineOperand StubMOHi =
1723 AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
1724 MCOperand StubMCHi, StubMCLo;
1725
1726 MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
1727 MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
1728
1729 EmitToStreamer(
1730 *OutStreamer,
1731 MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi));
1732
1733 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui)
1734 .addReg(DstReg)
1735 .addReg(DstReg)
1736 .addOperand(StubMCLo));
1737}
1738
1739void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
1740 unsigned InstsEmitted = 0;
1741 auto EmitAndIncrement = [this, &InstsEmitted](const MCInst &Inst) {
1742 EmitToStreamer(*OutStreamer, Inst);
1743 ++InstsEmitted;
1744 };
1745
1746 const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC;
1747 MachineOperand GAOp = MI.getOperand(0);
1748 const uint64_t KeyC = MI.getOperand(1).getImm();
1749 assert(KeyC <= AArch64PACKey::LAST &&
1750 "key is out of range [0, AArch64PACKey::LAST]");
1751 const auto Key = (AArch64PACKey::ID)KeyC;
1752 const unsigned AddrDisc = MI.getOperand(2).getReg();
1753 const uint64_t Disc = MI.getOperand(3).getImm();
1754 assert(isUInt<16>(Disc) &&
1755 "constant discriminator is out of range [0, 0xffff]");
1756
1757 const int64_t Offset = GAOp.getOffset();
1758 GAOp.setOffset(0);
1759
1760 // Emit:
1761 // target materialization:
1762 // - via GOT:
1763 // adrp x16, :got:target
1764 // ldr x16, [x16, :got_lo12:target]
1765 // add offset to x16 if offset != 0
1766 //
1767 // - direct:
1768 // adrp x16, target
1769 // add x16, x16, :lo12:target
1770 // add offset to x16 if offset != 0
1771 //
1772 // add offset to x16:
1773 // - abs(offset) fits 24 bits:
1774 // add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions)
1775 // - abs(offset) does not fit 24 bits:
1776 // - offset < 0:
1777 // movn+movk sequence filling x17 register with the offset (up to 4
1778 // instructions)
1779 // add x16, x16, x17
1780 // - offset > 0:
1781 // movz+movk sequence filling x17 register with the offset (up to 4
1782 // instructions)
1783 // add x16, x16, x17
1784 //
1785 // signing:
1786 // - 0 discriminator:
1787 // paciza x16
1788 // - Non-0 discriminator, no address discriminator:
1789 // mov x17, #Disc
1790 // pacia x16, x17
1791 // - address discriminator (with potentially folded immediate discriminator):
1792 // pacia x16, xAddrDisc
1793
1794 MachineOperand GAMOHi(GAOp), GAMOLo(GAOp);
1795 MCOperand GAMCHi, GAMCLo;
1796
1797 GAMOHi.setTargetFlags(AArch64II::MO_PAGE);
1798 GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
1799 if (IsGOTLoad) {
1800 GAMOHi.addTargetFlag(AArch64II::MO_GOT);
1801 GAMOLo.addTargetFlag(AArch64II::MO_GOT);
1802 }
1803
1804 MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
1805 MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
1806
1807 EmitAndIncrement(
1808 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X16).addOperand(GAMCHi));
1809
1810 if (IsGOTLoad) {
1811 EmitAndIncrement(MCInstBuilder(AArch64::LDRXui)
1812 .addReg(AArch64::X16)
1813 .addReg(AArch64::X16)
1814 .addOperand(GAMCLo));
1815 } else {
1816 EmitAndIncrement(MCInstBuilder(AArch64::ADDXri)
1817 .addReg(AArch64::X16)
1818 .addReg(AArch64::X16)
1819 .addOperand(GAMCLo)
1820 .addImm(0));
1821 }
1822
1823 if (Offset != 0) {
1824 const uint64_t AbsOffset = (Offset > 0 ? Offset : -((uint64_t)Offset));
1825 const bool IsNeg = Offset < 0;
1826 if (isUInt<24>(AbsOffset)) {
1827 for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
1828 BitPos += 12) {
1829 EmitAndIncrement(
1830 MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri)
1831 .addReg(AArch64::X16)
1832 .addReg(AArch64::X16)
1833 .addImm((AbsOffset >> BitPos) & 0xfff)
1834 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
1835 }
1836 } else {
1837 const uint64_t UOffset = Offset;
1838 EmitAndIncrement(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
1839 .addReg(AArch64::X17)
1840 .addImm((IsNeg ? ~UOffset : UOffset) & 0xffff)
1841 .addImm(/*shift=*/0));
1842 auto NeedMovk = [IsNeg, UOffset](int BitPos) -> bool {
1843 assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
1844 uint64_t Shifted = UOffset >> BitPos;
1845 if (!IsNeg)
1846 return Shifted != 0;
1847 for (int I = 0; I != 64 - BitPos; I += 16)
1848 if (((Shifted >> I) & 0xffff) != 0xffff)
1849 return true;
1850 return false;
1851 };
1852 for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) {
1853 EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
1854 .addReg(AArch64::X17)
1855 .addReg(AArch64::X17)
1856 .addImm((UOffset >> BitPos) & 0xffff)
1857 .addImm(/*shift=*/BitPos));
1858 }
1859 EmitAndIncrement(MCInstBuilder(AArch64::ADDXrs)
1860 .addReg(AArch64::X16)
1861 .addReg(AArch64::X16)
1862 .addReg(AArch64::X17)
1863 .addImm(/*shift=*/0));
1864 }
1865 }
1866
1867 unsigned DiscReg = AddrDisc;
1868 if (Disc != 0) {
1869 if (AddrDisc != AArch64::XZR) {
1870 EmitAndIncrement(MCInstBuilder(AArch64::ORRXrs)
1871 .addReg(AArch64::X17)
1872 .addReg(AArch64::XZR)
1873 .addReg(AddrDisc)
1874 .addImm(0));
1875 EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
1876 .addReg(AArch64::X17)
1877 .addReg(AArch64::X17)
1878 .addImm(Disc)
1879 .addImm(/*shift=*/48));
1880 } else {
1881 EmitAndIncrement(MCInstBuilder(AArch64::MOVZXi)
1882 .addReg(AArch64::X17)
1883 .addImm(Disc)
1884 .addImm(/*shift=*/0));
1885 }
1886 DiscReg = AArch64::X17;
1887 }
1888
1889 auto MIB = MCInstBuilder(getPACOpcodeForKey(Key, DiscReg == AArch64::XZR))
1890 .addReg(AArch64::X16)
1891 .addReg(AArch64::X16);
1892 if (DiscReg != AArch64::XZR)
1893 MIB.addReg(DiscReg);
1894 EmitAndIncrement(MIB);
1895
1896 assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4);
1897}
1898
1899// Simple pseudo-instructions have their lowering (with expansion to real
1900// instructions) auto-generated.
1901#include "AArch64GenMCPseudoLowering.inc"
1902
1903void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
1904 AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
1905
1906 // Do any auto-generated pseudo lowerings.
1907 if (emitPseudoExpansionLowering(*OutStreamer, MI))
1908 return;
1909
1910 if (MI->getOpcode() == AArch64::ADRP) {
1911 for (auto &Opd : MI->operands()) {
1912 if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) ==
1913 "swift_async_extendedFramePointerFlags") {
1914 ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true;
1915 }
1916 }
1917 }
1918
1919 if (AArch64FI->getLOHRelated().count(MI)) {
1920 // Generate a label for LOH related instruction
1921 MCSymbol *LOHLabel = createTempSymbol("loh");
1922 // Associate the instruction with the label
1923 LOHInstToLabel[MI] = LOHLabel;
1924 OutStreamer->emitLabel(LOHLabel);
1925 }
1926
1928 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1929 // Do any manual lowerings.
1930 switch (MI->getOpcode()) {
1931 default:
1932 break;
1933 case AArch64::HINT: {
1934 // CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for
1935 // -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be
1936 // non-empty. If MI is the initial BTI, place the
1937 // __patchable_function_entries label after BTI.
1938 if (CurrentPatchableFunctionEntrySym &&
1939 CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
1940 MI == &MF->front().front()) {
1941 int64_t Imm = MI->getOperand(0).getImm();
1942 if ((Imm & 32) && (Imm & 6)) {
1943 MCInst Inst;
1944 MCInstLowering.Lower(MI, Inst);
1945 EmitToStreamer(*OutStreamer, Inst);
1946 CurrentPatchableFunctionEntrySym = createTempSymbol("patch");
1947 OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym);
1948 return;
1949 }
1950 }
1951 break;
1952 }
1953 case AArch64::MOVMCSym: {
1954 Register DestReg = MI->getOperand(0).getReg();
1955 const MachineOperand &MO_Sym = MI->getOperand(1);
1956 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
1957 MCOperand Hi_MCSym, Lo_MCSym;
1958
1959 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
1960 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
1961
1962 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
1963 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
1964
1965 MCInst MovZ;
1966 MovZ.setOpcode(AArch64::MOVZXi);
1967 MovZ.addOperand(MCOperand::createReg(DestReg));
1968 MovZ.addOperand(Hi_MCSym);
1970 EmitToStreamer(*OutStreamer, MovZ);
1971
1972 MCInst MovK;
1973 MovK.setOpcode(AArch64::MOVKXi);
1974 MovK.addOperand(MCOperand::createReg(DestReg));
1975 MovK.addOperand(MCOperand::createReg(DestReg));
1976 MovK.addOperand(Lo_MCSym);
1978 EmitToStreamer(*OutStreamer, MovK);
1979 return;
1980 }
1981 case AArch64::MOVIv2d_ns:
1982 // It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0".
1983 // as movi is more efficient across all cores. Newer cores can eliminate
1984 // fmovs early and there is no difference with movi, but this not true for
1985 // all implementations.
1986 //
1987 // The floating-point version doesn't quite work in rare cases on older
1988 // CPUs, so on those targets we lower this instruction to movi.16b instead.
1989 if (STI->hasZeroCycleZeroingFPWorkaround() &&
1990 MI->getOperand(1).getImm() == 0) {
1991 MCInst TmpInst;
1992 TmpInst.setOpcode(AArch64::MOVIv16b_ns);
1993 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
1994 TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
1995 EmitToStreamer(*OutStreamer, TmpInst);
1996 return;
1997 }
1998 break;
1999
2000 case AArch64::DBG_VALUE:
2001 case AArch64::DBG_VALUE_LIST:
2002 if (isVerbose() && OutStreamer->hasRawTextSupport()) {
2003 SmallString<128> TmpStr;
2004 raw_svector_ostream OS(TmpStr);
2005 PrintDebugValueComment(MI, OS);
2006 OutStreamer->emitRawText(StringRef(OS.str()));
2007 }
2008 return;
2009
2010 case AArch64::EMITBKEY: {
2011 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
2012 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
2013 ExceptionHandlingType != ExceptionHandling::ARM)
2014 return;
2015
2016 if (getFunctionCFISectionType(*MF) == CFISection::None)
2017 return;
2018
2019 OutStreamer->emitCFIBKeyFrame();
2020 return;
2021 }
2022
2023 case AArch64::EMITMTETAGGED: {
2024 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
2025 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
2026 ExceptionHandlingType != ExceptionHandling::ARM)
2027 return;
2028
2029 if (getFunctionCFISectionType(*MF) != CFISection::None)
2030 OutStreamer->emitCFIMTETaggedFrame();
2031 return;
2032 }
2033
2034 case AArch64::LOADauthptrstatic:
2035 LowerLOADauthptrstatic(*MI);
2036 return;
2037
2038 case AArch64::LOADgotPAC:
2039 case AArch64::MOVaddrPAC:
2040 LowerMOVaddrPAC(*MI);
2041 return;
2042
2043 case AArch64::BLRA:
2044 emitPtrauthBranch(MI);
2045 return;
2046
2047 // Tail calls use pseudo instructions so they have the proper code-gen
2048 // attributes (isCall, isReturn, etc.). We lower them to the real
2049 // instruction here.
2050 case AArch64::AUTH_TCRETURN:
2051 case AArch64::AUTH_TCRETURN_BTI: {
2052 const uint64_t Key = MI->getOperand(2).getImm();
2053 assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
2054 "Invalid auth key for tail-call return");
2055
2056 const uint64_t Disc = MI->getOperand(3).getImm();
2057 assert(isUInt<16>(Disc) && "Integer discriminator is too wide");
2058
2059 Register AddrDisc = MI->getOperand(4).getReg();
2060
2061 Register ScratchReg = MI->getOperand(0).getReg() == AArch64::X16
2062 ? AArch64::X17
2063 : AArch64::X16;
2064
2065 unsigned DiscReg = AddrDisc;
2066 if (Disc) {
2067 if (AddrDisc != AArch64::NoRegister) {
2068 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
2069 .addReg(ScratchReg)
2070 .addReg(AArch64::XZR)
2071 .addReg(AddrDisc)
2072 .addImm(0));
2073 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
2074 .addReg(ScratchReg)
2075 .addReg(ScratchReg)
2076 .addImm(Disc)
2077 .addImm(/*shift=*/48));
2078 } else {
2079 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
2080 .addReg(ScratchReg)
2081 .addImm(Disc)
2082 .addImm(/*shift=*/0));
2083 }
2084 DiscReg = ScratchReg;
2085 }
2086
2087 const bool IsZero = DiscReg == AArch64::NoRegister;
2088 const unsigned Opcodes[2][2] = {{AArch64::BRAA, AArch64::BRAAZ},
2089 {AArch64::BRAB, AArch64::BRABZ}};
2090
2091 MCInst TmpInst;
2092 TmpInst.setOpcode(Opcodes[Key][IsZero]);
2093 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
2094 if (!IsZero)
2095 TmpInst.addOperand(MCOperand::createReg(DiscReg));
2096 EmitToStreamer(*OutStreamer, TmpInst);
2097 return;
2098 }
2099
2100 case AArch64::TCRETURNri:
2101 case AArch64::TCRETURNrix16x17:
2102 case AArch64::TCRETURNrix17:
2103 case AArch64::TCRETURNrinotx16:
2104 case AArch64::TCRETURNriALL: {
2105 MCInst TmpInst;
2106 TmpInst.setOpcode(AArch64::BR);
2107 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
2108 EmitToStreamer(*OutStreamer, TmpInst);
2109 return;
2110 }
2111 case AArch64::TCRETURNdi: {
2112 MCOperand Dest;
2113 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
2114 MCInst TmpInst;
2115 TmpInst.setOpcode(AArch64::B);
2116 TmpInst.addOperand(Dest);
2117 EmitToStreamer(*OutStreamer, TmpInst);
2118 return;
2119 }
2120 case AArch64::SpeculationBarrierISBDSBEndBB: {
2121 // Print DSB SYS + ISB
2122 MCInst TmpInstDSB;
2123 TmpInstDSB.setOpcode(AArch64::DSB);
2124 TmpInstDSB.addOperand(MCOperand::createImm(0xf));
2125 EmitToStreamer(*OutStreamer, TmpInstDSB);
2126 MCInst TmpInstISB;
2127 TmpInstISB.setOpcode(AArch64::ISB);
2128 TmpInstISB.addOperand(MCOperand::createImm(0xf));
2129 EmitToStreamer(*OutStreamer, TmpInstISB);
2130 return;
2131 }
2132 case AArch64::SpeculationBarrierSBEndBB: {
2133 // Print SB
2134 MCInst TmpInstSB;
2135 TmpInstSB.setOpcode(AArch64::SB);
2136 EmitToStreamer(*OutStreamer, TmpInstSB);
2137 return;
2138 }
2139 case AArch64::TLSDESC_CALLSEQ: {
2140 /// lower this to:
2141 /// adrp x0, :tlsdesc:var
2142 /// ldr x1, [x0, #:tlsdesc_lo12:var]
2143 /// add x0, x0, #:tlsdesc_lo12:var
2144 /// .tlsdesccall var
2145 /// blr x1
2146 /// (TPIDR_EL0 offset now in x0)
2147 const MachineOperand &MO_Sym = MI->getOperand(0);
2148 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
2149 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
2150 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
2151 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
2152 MCInstLowering.lowerOperand(MO_Sym, Sym);
2153 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
2154 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
2155
2156 MCInst Adrp;
2157 Adrp.setOpcode(AArch64::ADRP);
2158 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
2159 Adrp.addOperand(SymTLSDesc);
2160 EmitToStreamer(*OutStreamer, Adrp);
2161
2162 MCInst Ldr;
2163 if (STI->isTargetILP32()) {
2164 Ldr.setOpcode(AArch64::LDRWui);
2165 Ldr.addOperand(MCOperand::createReg(AArch64::W1));
2166 } else {
2167 Ldr.setOpcode(AArch64::LDRXui);
2168 Ldr.addOperand(MCOperand::createReg(AArch64::X1));
2169 }
2170 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
2171 Ldr.addOperand(SymTLSDescLo12);
2173 EmitToStreamer(*OutStreamer, Ldr);
2174
2175 MCInst Add;
2176 if (STI->isTargetILP32()) {
2177 Add.setOpcode(AArch64::ADDWri);
2178 Add.addOperand(MCOperand::createReg(AArch64::W0));
2179 Add.addOperand(MCOperand::createReg(AArch64::W0));
2180 } else {
2181 Add.setOpcode(AArch64::ADDXri);
2182 Add.addOperand(MCOperand::createReg(AArch64::X0));
2183 Add.addOperand(MCOperand::createReg(AArch64::X0));
2184 }
2185 Add.addOperand(SymTLSDescLo12);
2187 EmitToStreamer(*OutStreamer, Add);
2188
2189 // Emit a relocation-annotation. This expands to no code, but requests
2190 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
2191 MCInst TLSDescCall;
2192 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
2193 TLSDescCall.addOperand(Sym);
2194 EmitToStreamer(*OutStreamer, TLSDescCall);
2195
2196 MCInst Blr;
2197 Blr.setOpcode(AArch64::BLR);
2198 Blr.addOperand(MCOperand::createReg(AArch64::X1));
2199 EmitToStreamer(*OutStreamer, Blr);
2200
2201 return;
2202 }
2203
2204 case AArch64::JumpTableDest32:
2205 case AArch64::JumpTableDest16:
2206 case AArch64::JumpTableDest8:
2207 LowerJumpTableDest(*OutStreamer, *MI);
2208 return;
2209
2210 case AArch64::FMOVH0:
2211 case AArch64::FMOVS0:
2212 case AArch64::FMOVD0:
2213 emitFMov0(*MI);
2214 return;
2215
2216 case AArch64::MOPSMemoryCopyPseudo:
2217 case AArch64::MOPSMemoryMovePseudo:
2218 case AArch64::MOPSMemorySetPseudo:
2219 case AArch64::MOPSMemorySetTaggingPseudo:
2220 LowerMOPS(*OutStreamer, *MI);
2221 return;
2222
2223 case TargetOpcode::STACKMAP:
2224 return LowerSTACKMAP(*OutStreamer, SM, *MI);
2225
2226 case TargetOpcode::PATCHPOINT:
2227 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
2228
2229 case TargetOpcode::STATEPOINT:
2230 return LowerSTATEPOINT(*OutStreamer, SM, *MI);
2231
2232 case TargetOpcode::FAULTING_OP:
2233 return LowerFAULTING_OP(*MI);
2234
2235 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
2236 LowerPATCHABLE_FUNCTION_ENTER(*MI);
2237 return;
2238
2239 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
2240 LowerPATCHABLE_FUNCTION_EXIT(*MI);
2241 return;
2242
2243 case TargetOpcode::PATCHABLE_TAIL_CALL:
2244 LowerPATCHABLE_TAIL_CALL(*MI);
2245 return;
2246 case TargetOpcode::PATCHABLE_EVENT_CALL:
2247 return LowerPATCHABLE_EVENT_CALL(*MI, false);
2248 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
2249 return LowerPATCHABLE_EVENT_CALL(*MI, true);
2250
2251 case AArch64::KCFI_CHECK:
2252 LowerKCFI_CHECK(*MI);
2253 return;
2254
2255 case AArch64::HWASAN_CHECK_MEMACCESS:
2256 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
2257 case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
2258 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
2259 LowerHWASAN_CHECK_MEMACCESS(*MI);
2260 return;
2261
2262 case AArch64::SEH_StackAlloc:
2263 TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
2264 return;
2265
2266 case AArch64::SEH_SaveFPLR:
2267 TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
2268 return;
2269
2270 case AArch64::SEH_SaveFPLR_X:
2271 assert(MI->getOperand(0).getImm() < 0 &&
2272 "Pre increment SEH opcode must have a negative offset");
2273 TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
2274 return;
2275
2276 case AArch64::SEH_SaveReg:
2277 TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
2278 MI->getOperand(1).getImm());
2279 return;
2280
2281 case AArch64::SEH_SaveReg_X:
2282 assert(MI->getOperand(1).getImm() < 0 &&
2283 "Pre increment SEH opcode must have a negative offset");
2284 TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
2285 -MI->getOperand(1).getImm());
2286 return;
2287
2288 case AArch64::SEH_SaveRegP:
2289 if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 &&
2290 MI->getOperand(0).getImm() <= 28) {
2291 assert((MI->getOperand(0).getImm() - 19) % 2 == 0 &&
2292 "Register paired with LR must be odd");
2293 TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(),
2294 MI->getOperand(2).getImm());
2295 return;
2296 }
2297 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2298 "Non-consecutive registers not allowed for save_regp");
2299 TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
2300 MI->getOperand(2).getImm());
2301 return;
2302
2303 case AArch64::SEH_SaveRegP_X:
2304 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2305 "Non-consecutive registers not allowed for save_regp_x");
2306 assert(MI->getOperand(2).getImm() < 0 &&
2307 "Pre increment SEH opcode must have a negative offset");
2308 TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
2309 -MI->getOperand(2).getImm());
2310 return;
2311
2312 case AArch64::SEH_SaveFReg:
2313 TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
2314 MI->getOperand(1).getImm());
2315 return;
2316
2317 case AArch64::SEH_SaveFReg_X:
2318 assert(MI->getOperand(1).getImm() < 0 &&
2319 "Pre increment SEH opcode must have a negative offset");
2320 TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
2321 -MI->getOperand(1).getImm());
2322 return;
2323
2324 case AArch64::SEH_SaveFRegP:
2325 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2326 "Non-consecutive registers not allowed for save_regp");
2327 TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
2328 MI->getOperand(2).getImm());
2329 return;
2330
2331 case AArch64::SEH_SaveFRegP_X:
2332 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2333 "Non-consecutive registers not allowed for save_regp_x");
2334 assert(MI->getOperand(2).getImm() < 0 &&
2335 "Pre increment SEH opcode must have a negative offset");
2336 TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
2337 -MI->getOperand(2).getImm());
2338 return;
2339
2340 case AArch64::SEH_SetFP:
2342 return;
2343
2344 case AArch64::SEH_AddFP:
2345 TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm());
2346 return;
2347
2348 case AArch64::SEH_Nop:
2349 TS->emitARM64WinCFINop();
2350 return;
2351
2352 case AArch64::SEH_PrologEnd:
2354 return;
2355
2356 case AArch64::SEH_EpilogStart:
2358 return;
2359
2360 case AArch64::SEH_EpilogEnd:
2362 return;
2363
2364 case AArch64::SEH_PACSignLR:
2366 return;
2367
2368 case AArch64::SEH_SaveAnyRegQP:
2369 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
2370 "Non-consecutive registers not allowed for save_any_reg");
2371 assert(MI->getOperand(2).getImm() >= 0 &&
2372 "SaveAnyRegQP SEH opcode offset must be non-negative");
2373 assert(MI->getOperand(2).getImm() <= 1008 &&
2374 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
2375 TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(),
2376 MI->getOperand(2).getImm());
2377 return;
2378
2379 case AArch64::SEH_SaveAnyRegQPX:
2380 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
2381 "Non-consecutive registers not allowed for save_any_reg");
2382 assert(MI->getOperand(2).getImm() < 0 &&
2383 "SaveAnyRegQPX SEH opcode offset must be negative");
2384 assert(MI->getOperand(2).getImm() >= -1008 &&
2385 "SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
2386 TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(),
2387 -MI->getOperand(2).getImm());
2388 return;
2389 }
2390
2391 // Finally, do the automated lowerings for everything else.
2392 MCInst TmpInst;
2393 MCInstLowering.Lower(MI, TmpInst);
2394 EmitToStreamer(*OutStreamer, TmpInst);
2395}
2396
2397void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
2398 MCSymbol *LazyPointer) {
2399 // _ifunc:
2400 // adrp x16, lazy_pointer@GOTPAGE
2401 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
2402 // ldr x16, [x16]
2403 // br x16
2404
2405 {
2406 MCInst Adrp;
2407 Adrp.setOpcode(AArch64::ADRP);
2408 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
2409 MCOperand SymPage;
2410 MCInstLowering.lowerOperand(
2413 SymPage);
2414 Adrp.addOperand(SymPage);
2415 OutStreamer->emitInstruction(Adrp, *STI);
2416 }
2417
2418 {
2419 MCInst Ldr;
2420 Ldr.setOpcode(AArch64::LDRXui);
2421 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2422 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2423 MCOperand SymPageOff;
2424 MCInstLowering.lowerOperand(
2427 SymPageOff);
2428 Ldr.addOperand(SymPageOff);
2430 OutStreamer->emitInstruction(Ldr, *STI);
2431 }
2432
2433 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
2434 .addReg(AArch64::X16)
2435 .addReg(AArch64::X16)
2436 .addImm(0),
2437 *STI);
2438
2439 OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
2440 ? AArch64::BRAAZ
2441 : AArch64::BR)
2442 .addReg(AArch64::X16),
2443 *STI);
2444}
2445
2446void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
2447 const GlobalIFunc &GI,
2448 MCSymbol *LazyPointer) {
2449 // These stub helpers are only ever called once, so here we're optimizing for
2450 // minimum size by using the pre-indexed store variants, which saves a few
2451 // bytes of instructions to bump & restore sp.
2452
2453 // _ifunc.stub_helper:
2454 // stp fp, lr, [sp, #-16]!
2455 // mov fp, sp
2456 // stp x1, x0, [sp, #-16]!
2457 // stp x3, x2, [sp, #-16]!
2458 // stp x5, x4, [sp, #-16]!
2459 // stp x7, x6, [sp, #-16]!
2460 // stp d1, d0, [sp, #-16]!
2461 // stp d3, d2, [sp, #-16]!
2462 // stp d5, d4, [sp, #-16]!
2463 // stp d7, d6, [sp, #-16]!
2464 // bl _resolver
2465 // adrp x16, lazy_pointer@GOTPAGE
2466 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
2467 // str x0, [x16]
2468 // mov x16, x0
2469 // ldp d7, d6, [sp], #16
2470 // ldp d5, d4, [sp], #16
2471 // ldp d3, d2, [sp], #16
2472 // ldp d1, d0, [sp], #16
2473 // ldp x7, x6, [sp], #16
2474 // ldp x5, x4, [sp], #16
2475 // ldp x3, x2, [sp], #16
2476 // ldp x1, x0, [sp], #16
2477 // ldp fp, lr, [sp], #16
2478 // br x16
2479
2480 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
2481 .addReg(AArch64::SP)
2482 .addReg(AArch64::FP)
2483 .addReg(AArch64::LR)
2484 .addReg(AArch64::SP)
2485 .addImm(-2),
2486 *STI);
2487
2488 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
2489 .addReg(AArch64::FP)
2490 .addReg(AArch64::SP)
2491 .addImm(0)
2492 .addImm(0),
2493 *STI);
2494
2495 for (int I = 0; I != 4; ++I)
2496 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
2497 .addReg(AArch64::SP)
2498 .addReg(AArch64::X1 + 2 * I)
2499 .addReg(AArch64::X0 + 2 * I)
2500 .addReg(AArch64::SP)
2501 .addImm(-2),
2502 *STI);
2503
2504 for (int I = 0; I != 4; ++I)
2505 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
2506 .addReg(AArch64::SP)
2507 .addReg(AArch64::D1 + 2 * I)
2508 .addReg(AArch64::D0 + 2 * I)
2509 .addReg(AArch64::SP)
2510 .addImm(-2),
2511 *STI);
2512
2513 OutStreamer->emitInstruction(
2514 MCInstBuilder(AArch64::BL)
2516 *STI);
2517
2518 {
2519 MCInst Adrp;
2520 Adrp.setOpcode(AArch64::ADRP);
2521 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
2522 MCOperand SymPage;
2523 MCInstLowering.lowerOperand(
2524 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
2526 SymPage);
2527 Adrp.addOperand(SymPage);
2528 OutStreamer->emitInstruction(Adrp, *STI);
2529 }
2530
2531 {
2532 MCInst Ldr;
2533 Ldr.setOpcode(AArch64::LDRXui);
2534 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2535 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2536 MCOperand SymPageOff;
2537 MCInstLowering.lowerOperand(
2538 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
2540 SymPageOff);
2541 Ldr.addOperand(SymPageOff);
2543 OutStreamer->emitInstruction(Ldr, *STI);
2544 }
2545
2546 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
2547 .addReg(AArch64::X0)
2548 .addReg(AArch64::X16)
2549 .addImm(0),
2550 *STI);
2551
2552 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
2553 .addReg(AArch64::X16)
2554 .addReg(AArch64::X0)
2555 .addImm(0)
2556 .addImm(0),
2557 *STI);
2558
2559 for (int I = 3; I != -1; --I)
2560 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
2561 .addReg(AArch64::SP)
2562 .addReg(AArch64::D1 + 2 * I)
2563 .addReg(AArch64::D0 + 2 * I)
2564 .addReg(AArch64::SP)
2565 .addImm(2),
2566 *STI);
2567
2568 for (int I = 3; I != -1; --I)
2569 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
2570 .addReg(AArch64::SP)
2571 .addReg(AArch64::X1 + 2 * I)
2572 .addReg(AArch64::X0 + 2 * I)
2573 .addReg(AArch64::SP)
2574 .addImm(2),
2575 *STI);
2576
2577 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
2578 .addReg(AArch64::SP)
2579 .addReg(AArch64::FP)
2580 .addReg(AArch64::LR)
2581 .addReg(AArch64::SP)
2582 .addImm(2),
2583 *STI);
2584
2585 OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
2586 ? AArch64::BRAAZ
2587 : AArch64::BR)
2588 .addReg(AArch64::X16),
2589 *STI);
2590}
2591
2592const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV) {
2593 if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
2594 return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0),
2595 OutContext);
2596 }
2597
2598 return AsmPrinter::lowerConstant(CV);
2599}
2600
2601// Force static initialization.
2608}
static void emitAuthenticatedPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel, const MCExpr *StubAuthPtrRef)
LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter()
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
MachineBasicBlock & MBB
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_EXTERNAL_VISIBILITY
Definition: Compiler.h:135
std::string Name
uint64_t Size
Symbol * Sym
Definition: ELF_riscv.cpp:479
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Module.h This file contains the declarations for the Module class.
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
#define P(N)
const char LLVMTargetMachineRef TM
static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
This file defines the SmallString class.
This file defines the SmallVector class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition: Value.cpp:469
static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO, char Mode, raw_ostream &O)
static const AArch64AuthMCExpr * create(const MCExpr *Expr, uint16_t Discriminator, AArch64PACKey::ID Key, bool HasAddressDiversity, MCContext &Ctx)
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
std::optional< std::string > getOutliningStyle() const
static const char * getRegisterName(MCRegister Reg, unsigned AltIdx=AArch64::NoRegAltName)
static const AArch64MCExpr * create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx)
AArch64MCInstLower - This class is used to lower an MachineInstr into an MCInst.
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
virtual void emitARM64WinCFISaveRegP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveRegPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegQP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFRegPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveRegX(unsigned Reg, int Offset)
virtual void emitARM64WinCFIAllocStack(unsigned Size)
virtual void emitARM64WinCFISaveFPLRX(int Offset)
virtual void emitDirectiveVariantPCS(MCSymbol *Symbol)
Callback used to implement the .variant_pcs directive.
virtual void emitARM64WinCFIAddFP(unsigned Size)
virtual void emitARM64WinCFISaveFPLR(int Offset)
virtual void emitARM64WinCFISaveFRegP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFRegX(unsigned Reg, int Offset)
void emitNoteSection(unsigned Flags, uint64_t PAuthABIPlatform=-1, uint64_t PAuthABIVersion=-1)
Callback used to implement the .note.gnu.property section.
virtual void emitARM64WinCFISaveReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveLRPair(unsigned Reg, int Offset)
This implementation is used for AArch64 ELF targets (Linux in particular).
AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.
Class for arbitrary precision integers.
Definition: APInt.h:78
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:86
virtual void emitInstruction(const MachineInstr *)
Targets should implement this to emit instructions.
Definition: AsmPrinter.h:555
virtual const MCExpr * lowerConstantPtrAuth(const ConstantPtrAuth &CPA)
Definition: AsmPrinter.h:576
void emitXRayTable()
Emit a table with all XRay instrumentation points.
virtual MCSymbol * GetCPISymbol(unsigned CPID) const
Return the symbol for the specified constant pool entry.
virtual void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI, MCSymbol *LazyPointer)
Definition: AsmPrinter.h:604
virtual void emitJumpTableInfo()
Print assembly representations of the jump tables used by the current function to the current output ...
virtual void SetupMachineFunction(MachineFunction &MF)
This should be called when a new MachineFunction is being processed from runOnMachineFunction.
void emitFunctionBody()
This method emits the body and trailer for a function.
virtual void emitStartOfAsmFile(Module &)
This virtual method can be overridden by targets that want to emit something at the start of their fi...
Definition: AsmPrinter.h:531
virtual void emitEndOfAsmFile(Module &)
This virtual method can be overridden by targets that want to emit something at the end of their file...
Definition: AsmPrinter.h:535
virtual void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI, MCSymbol *LazyPointer)
Definition: AsmPrinter.h:598
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
Definition: AsmPrinter.cpp:425
virtual bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const
Definition: AsmPrinter.h:903
virtual const MCSubtargetInfo * getIFuncMCSubtargetInfo() const
getSubtargetInfo() cannot be used where this is needed because we don't have a MachineFunction when w...
Definition: AsmPrinter.h:594
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition: AsmPrinter.h:384
virtual const MCExpr * lowerConstant(const Constant *CV)
Lower the specified LLVM Constant to an MCExpr.
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
virtual void emitFunctionBodyEnd()
Targets can override this to emit stuff after the last basic block in the function.
Definition: AsmPrinter.h:543
virtual void emitFunctionEntryLabel()
EmitFunctionEntryLabel - Emit the label that is the entrypoint for the function.
virtual std::tuple< const MCSymbol *, uint64_t, const MCSymbol *, codeview::JumpTableEntrySize > getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr, const MCSymbol *BranchLabel) const
Gets information required to create a CodeView debug symbol for a jump table.
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition: Constants.h:155
A signed pointer, in the ptrauth sense.
Definition: Constants.h:1012
Constant * getPointer() const
The pointer that is signed in this ptrauth signed pointer.
Definition: Constants.h:1037
ConstantInt * getKey() const
The Key ID, an i32 constant.
Definition: Constants.h:1040
bool hasAddressDiscriminator() const
Whether there is any non-null address discriminator.
Definition: Constants.h:1055
ConstantInt * getDiscriminator() const
The integer discriminator, an i64 constant, or 0.
Definition: Constants.h:1043
This is an important base class in LLVM.
Definition: Constant.h:42
This class represents an Operation in the Expression.
const Constant * getResolver() const
Definition: GlobalIFunc.h:70
bool hasLocalLinkage() const
Definition: GlobalValue.h:528
void emitError(uint64_t LocCookie, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
static const MCBinaryExpr * createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:612
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:532
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:617
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:193
Context object for machine code objects.
Definition: MCContext.h:83
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
MCInstBuilder & addReg(unsigned Reg)
Add a new register operand.
Definition: MCInstBuilder.h:37
MCInstBuilder & addImm(int64_t Val)
Add a new integer immediate operand.
Definition: MCInstBuilder.h:43
MCInstBuilder & addExpr(const MCExpr *Val)
Add a new MCExpr operand.
Definition: MCInstBuilder.h:61
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:184
void addOperand(const MCOperand Op)
Definition: MCInst.h:210
void setOpcode(unsigned Op)
Definition: MCInst.h:197
MCSection * getDataSection() const
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:36
static MCOperand createReg(unsigned Reg)
Definition: MCInst.h:134
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:162
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:141
uint16_t getEncodingValue(MCRegister RegNo) const
Returns the encoding for RegNo.
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition: MCSection.h:36
Streaming machine code generation interface.
Definition: MCStreamer.h:213
virtual void emitCFIBKeyFrame()
Definition: MCStreamer.cpp:248
virtual void beginCOFFSymbolDef(const MCSymbol *Symbol)
Start emitting COFF symbol definition.
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual void emitCOFFSymbolType(int Type)
Emit the type of the symbol.
virtual bool hasRawTextSupport() const
Return true if this asm streamer supports emitting unformatted text to the .s file with EmitRawText.
Definition: MCStreamer.h:345
virtual void endCOFFSymbolDef()
Marks the end of the symbol definition.
MCContext & getContext() const
Definition: MCStreamer.h:300
virtual void AddComment(const Twine &T, bool EOL=true)
Add a textual comment.
Definition: MCStreamer.h:364
virtual void emitCFIMTETaggedFrame()
Definition: MCStreamer.cpp:255
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
Definition: MCStreamer.cpp:179
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
Definition: MCStreamer.cpp:414
MCTargetStreamer * getTargetStreamer()
Definition: MCStreamer.h:309
void emitRawText(const Twine &String)
If this file is backed by a assembly streamer, this dumps the specified string in the output ....
Definition: MCStreamer.cpp:998
virtual void emitCOFFSymbolStorageClass(int StorageClass)
Emit the storage class of the symbol.
Generic base class for all target subtargets.
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:188
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:393
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:205
Metadata node.
Definition: Metadata.h:1067
MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
Definition: MachineInstr.h:69
iterator_range< mop_iterator > operands()
Definition: MachineInstr.h:685
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:579
const std::vector< MachineJumpTableEntry > & getJumpTables() const
MachineModuleInfoELF - This is a MachineModuleInfoImpl implementation for ELF targets.
MachineModuleInfoMachO - This is a MachineModuleInfoImpl implementation for MachO targets.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
static MachineOperand CreateMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
const GlobalValue * getGlobal() const
static MachineOperand CreateES(const char *SymName, unsigned TargetFlags=0)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
const BlockAddress * getBlockAddress() const
void setOffset(int64_t Offset)
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
int64_t getOffset() const
Return the offset from the symbol in this operand.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:94
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
MI-level patchpoint operands.
Definition: StackMaps.h:76
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
static SectionKind getMetadata()
Definition: SectionKind.h:188
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
MI-level stackmap operands.
Definition: StackMaps.h:35
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given stackmap should emit.
Definition: StackMaps.h:50
void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
Definition: StackMaps.cpp:569
void recordPatchPoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a patchpoint instruction.
Definition: StackMaps.cpp:548
void recordStackMap(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a stackmap instruction.
Definition: StackMaps.cpp:538
MI-level Statepoint operands.
Definition: StackMaps.h:158
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
virtual MCSection * getSectionForJumpTable(const Function &F, const TargetMachine &TM) const
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:77
MCRegister getRegister(unsigned i) const
Return the specified register in the class.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool regsOverlap(Register RegA, Register RegB) const
Returns true if the two registers are equal or alias each other.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:74
const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr) const
Accumulate the constant offset this value has compared to a base pointer.
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:1075
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:691
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_S
MO_S - Indicates that the bits of the symbol operand represented by MO_G0 etc are signed.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
Key
PAL metadata keys.
SymbolStorageClass
Storage class tells where and what the symbol represents.
Definition: COFF.h:217
@ IMAGE_SYM_CLASS_EXTERNAL
External symbol.
Definition: COFF.h:223
@ IMAGE_SYM_CLASS_STATIC
Static.
Definition: COFF.h:224
@ IMAGE_SYM_DTYPE_NULL
No complex type; simple scalar variable.
Definition: COFF.h:273
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
Definition: COFF.h:275
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
Definition: COFF.h:279
@ AArch64_VectorCall
Used between AArch64 Advanced SIMD functions.
Definition: CallingConv.h:221
@ AArch64_SVE_VectorCall
Used between AArch64 SVE functions.
Definition: CallingConv.h:224
@ GNU_PROPERTY_AARCH64_FEATURE_1_BTI
Definition: ELF.h:1768
@ GNU_PROPERTY_AARCH64_FEATURE_1_PAC
Definition: ELF.h:1769
@ GNU_PROPERTY_AARCH64_FEATURE_1_GCS
Definition: ELF.h:1770
@ SHT_PROGBITS
Definition: ELF.h:1068
@ SHF_ALLOC
Definition: ELF.h:1165
@ SHF_GROUP
Definition: ELF.h:1187
@ SHF_EXECINSTR
Definition: ELF.h:1168
@ S_REGULAR
S_REGULAR - Regular section.
Definition: MachO.h:127
Reg
All possible values of the reg field in the ModR/M byte.
constexpr double e
Definition: MathExtras.h:47
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
@ Offset
Definition: DWP.cpp:480
ExceptionHandling
Target & getTheAArch64beTarget()
Target & getTheAArch64leTarget()
static unsigned getXRegFromWReg(unsigned Reg)
static unsigned getXRegFromXRegTuple(unsigned RegTuple)
Target & getTheAArch64_32Target()
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
Target & getTheARM64_32Target()
@ MCAF_SubsectionsViaSymbols
.subsections_via_symbols (MachO)
Definition: MCDirectives.h:55
@ Add
Sum of integers.
static unsigned getWRegFromXReg(unsigned Reg)
Target & getTheARM64Target()
static unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero)
Return PAC opcode to be used for a ptrauth sign using the given key, or its PAC*Z variant that doesn'...
@ MCSA_Weak
.weak
Definition: MCDirectives.h:45
@ MCSA_Global
.type _foo, @gnu_unique_object
Definition: MCDirectives.h:30
@ MCSA_WeakAntiDep
.weak_anti_dep (COFF)
Definition: MCDirectives.h:49
@ MCSA_ELF_TypeFunction
.type _foo, STT_FUNC # aka @function
Definition: MCDirectives.h:23
@ MCSA_Hidden
.hidden (ELF)
Definition: MCDirectives.h:33
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...