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/MC/MCAsmInfo.h"
47#include "llvm/MC/MCContext.h"
48#include "llvm/MC/MCInst.h"
52#include "llvm/MC/MCStreamer.h"
53#include "llvm/MC/MCSymbol.h"
62#include <algorithm>
63#include <cassert>
64#include <cstdint>
65#include <map>
66#include <memory>
67
68using namespace llvm;
69
70#define DEBUG_TYPE "asm-printer"
71
72namespace {
73
74class AArch64AsmPrinter : public AsmPrinter {
75 AArch64MCInstLower MCInstLowering;
76 FaultMaps FM;
77 const AArch64Subtarget *STI;
78 bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false;
79
80public:
81 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
82 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
83 FM(*this) {}
84
85 StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
86
87 /// Wrapper for MCInstLowering.lowerOperand() for the
88 /// tblgen'erated pseudo lowering.
89 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
90 return MCInstLowering.lowerOperand(MO, MCOp);
91 }
92
93 void emitStartOfAsmFile(Module &M) override;
94 void emitJumpTableInfo() override;
95 std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
97 getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
98 const MCSymbol *BranchLabel) const override;
99
100 void emitFunctionEntryLabel() override;
101
102 void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
103
104 void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI);
105
106 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
107 const MachineInstr &MI);
108 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
109 const MachineInstr &MI);
110 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
111 const MachineInstr &MI);
112 void LowerFAULTING_OP(const MachineInstr &MI);
113
114 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
115 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
116 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
117 void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
118
119 typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
120 HwasanMemaccessTuple;
121 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
122 void LowerKCFI_CHECK(const MachineInstr &MI);
123 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
124 void emitHwasanMemaccessSymbols(Module &M);
125
126 void emitSled(const MachineInstr &MI, SledKind Kind);
127
128 // Emit the sequence for BLRA (authenticate + branch).
129 void emitPtrauthBranch(const MachineInstr *MI);
130 // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc.
131 unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc,
132 unsigned &InstsEmitted);
133
134 /// tblgen'erated driver function for lowering simple MI->MC
135 /// pseudo instructions.
136 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
137 const MachineInstr *MI);
138
139 void emitInstruction(const MachineInstr *MI) override;
140
141 void emitFunctionHeaderComment() override;
142
143 void getAnalysisUsage(AnalysisUsage &AU) const override {
145 AU.setPreservesAll();
146 }
147
148 bool runOnMachineFunction(MachineFunction &MF) override {
149 AArch64FI = MF.getInfo<AArch64FunctionInfo>();
150 STI = &MF.getSubtarget<AArch64Subtarget>();
151
153
154 if (STI->isTargetCOFF()) {
155 bool Local = MF.getFunction().hasLocalLinkage();
158 int Type =
160
161 OutStreamer->beginCOFFSymbolDef(CurrentFnSym);
162 OutStreamer->emitCOFFSymbolStorageClass(Scl);
163 OutStreamer->emitCOFFSymbolType(Type);
164 OutStreamer->endCOFFSymbolDef();
165 }
166
167 // Emit the rest of the function body.
169
170 // Emit the XRay table for this function.
172
173 // We didn't modify anything.
174 return false;
175 }
176
177 const MCExpr *lowerConstant(const Constant *CV) override;
178
179private:
180 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
181 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
182 bool printAsmRegInClass(const MachineOperand &MO,
183 const TargetRegisterClass *RC, unsigned AltName,
184 raw_ostream &O);
185
186 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
187 const char *ExtraCode, raw_ostream &O) override;
188 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
189 const char *ExtraCode, raw_ostream &O) override;
190
191 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
192
193 void emitFunctionBodyEnd() override;
194
195 MCSymbol *GetCPISymbol(unsigned CPID) const override;
196 void emitEndOfAsmFile(Module &M) override;
197
198 AArch64FunctionInfo *AArch64FI = nullptr;
199
200 /// Emit the LOHs contained in AArch64FI.
201 void emitLOHs();
202
203 /// Emit instruction to set float register to zero.
204 void emitFMov0(const MachineInstr &MI);
205
206 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
207
208 MInstToMCSymbol LOHInstToLabel;
209
211 return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
212 }
213
214 const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
215 assert(STI);
216 return STI;
217 }
218 void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
219 MCSymbol *LazyPointer) override;
221 MCSymbol *LazyPointer) override;
222};
223
224} // end anonymous namespace
225
226void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
227 const Triple &TT = TM.getTargetTriple();
228
229 if (TT.isOSBinFormatCOFF()) {
230 // Emit an absolute @feat.00 symbol
231 MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00"));
232 OutStreamer->beginCOFFSymbolDef(S);
233 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
234 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL);
235 OutStreamer->endCOFFSymbolDef();
236 int64_t Feat00Value = 0;
237
238 if (M.getModuleFlag("cfguard")) {
239 // Object is CFG-aware.
240 Feat00Value |= COFF::Feat00Flags::GuardCF;
241 }
242
243 if (M.getModuleFlag("ehcontguard")) {
244 // Object also has EHCont.
245 Feat00Value |= COFF::Feat00Flags::GuardEHCont;
246 }
247
248 if (M.getModuleFlag("ms-kernel")) {
249 // Object is compiled with /kernel.
250 Feat00Value |= COFF::Feat00Flags::Kernel;
251 }
252
253 OutStreamer->emitSymbolAttribute(S, MCSA_Global);
254 OutStreamer->emitAssignment(
255 S, MCConstantExpr::create(Feat00Value, MMI->getContext()));
256 }
257
258 if (!TT.isOSBinFormatELF())
259 return;
260
261 // Assemble feature flags that may require creation of a note section.
262 unsigned Flags = 0;
263 if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
264 M.getModuleFlag("branch-target-enforcement")))
265 if (BTE->getZExtValue())
267
268 if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
269 M.getModuleFlag("guarded-control-stack")))
270 if (GCS->getZExtValue())
272
273 if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
274 M.getModuleFlag("sign-return-address")))
275 if (Sign->getZExtValue())
277
278 uint64_t PAuthABIPlatform = -1;
279 if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
280 M.getModuleFlag("aarch64-elf-pauthabi-platform")))
281 PAuthABIPlatform = PAP->getZExtValue();
282 uint64_t PAuthABIVersion = -1;
283 if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
284 M.getModuleFlag("aarch64-elf-pauthabi-version")))
285 PAuthABIVersion = PAV->getZExtValue();
286
287 // Emit a .note.gnu.property section with the flags.
288 auto *TS =
289 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
290 TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion);
291}
292
293void AArch64AsmPrinter::emitFunctionHeaderComment() {
294 const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>();
295 std::optional<std::string> OutlinerString = FI->getOutliningStyle();
296 if (OutlinerString != std::nullopt)
297 OutStreamer->getCommentOS() << ' ' << OutlinerString;
298}
299
300void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
301{
302 const Function &F = MF->getFunction();
303 if (F.hasFnAttribute("patchable-function-entry")) {
304 unsigned Num;
305 if (F.getFnAttribute("patchable-function-entry")
306 .getValueAsString()
307 .getAsInteger(10, Num))
308 return;
309 emitNops(Num);
310 return;
311 }
312
313 emitSled(MI, SledKind::FUNCTION_ENTER);
314}
315
316void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
317 emitSled(MI, SledKind::FUNCTION_EXIT);
318}
319
320void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
321 emitSled(MI, SledKind::TAIL_CALL);
322}
323
324void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
325 static const int8_t NoopsInSledCount = 7;
326 // We want to emit the following pattern:
327 //
328 // .Lxray_sled_N:
329 // ALIGN
330 // B #32
331 // ; 7 NOP instructions (28 bytes)
332 // .tmpN
333 //
334 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
335 // over the full 32 bytes (8 instructions) with the following pattern:
336 //
337 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
338 // LDR W17, #12 ; W17 := function ID
339 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
340 // BLR X16 ; call the tracing trampoline
341 // ;DATA: 32 bits of function ID
342 // ;DATA: lower 32 bits of the address of the trampoline
343 // ;DATA: higher 32 bits of the address of the trampoline
344 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
345 //
346 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
347 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
348 OutStreamer->emitLabel(CurSled);
349 auto Target = OutContext.createTempSymbol();
350
351 // Emit "B #32" instruction, which jumps over the next 28 bytes.
352 // The operand has to be the number of 4-byte instructions to jump over,
353 // including the current instruction.
354 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
355
356 for (int8_t I = 0; I < NoopsInSledCount; I++)
357 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
358
359 OutStreamer->emitLabel(Target);
360 recordSled(CurSled, MI, Kind, 2);
361}
362
363// Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
364// (built-in functions __xray_customevent/__xray_typedevent).
365//
366// .Lxray_event_sled_N:
367// b 1f
368// save x0 and x1 (and also x2 for TYPED_EVENT_CALL)
369// set up x0 and x1 (and also x2 for TYPED_EVENT_CALL)
370// bl __xray_CustomEvent or __xray_TypedEvent
371// restore x0 and x1 (and also x2 for TYPED_EVENT_CALL)
372// 1:
373//
374// There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL.
375//
376// Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT.
377// After patching, b .+N will become a nop.
378void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
379 bool Typed) {
380 auto &O = *OutStreamer;
381 MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
382 O.emitLabel(CurSled);
383 MCInst MovX0Op0 = MCInstBuilder(AArch64::ORRXrs)
384 .addReg(AArch64::X0)
385 .addReg(AArch64::XZR)
386 .addReg(MI.getOperand(0).getReg())
387 .addImm(0);
388 MCInst MovX1Op1 = MCInstBuilder(AArch64::ORRXrs)
389 .addReg(AArch64::X1)
390 .addReg(AArch64::XZR)
391 .addReg(MI.getOperand(1).getReg())
392 .addImm(0);
393 bool MachO = TM.getTargetTriple().isOSBinFormatMachO();
395 OutContext.getOrCreateSymbol(
396 Twine(MachO ? "_" : "") +
397 (Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")),
398 OutContext);
399 if (Typed) {
400 O.AddComment("Begin XRay typed event");
401 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9));
402 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
403 .addReg(AArch64::SP)
404 .addReg(AArch64::X0)
405 .addReg(AArch64::X1)
406 .addReg(AArch64::SP)
407 .addImm(-4));
408 EmitToStreamer(O, MCInstBuilder(AArch64::STRXui)
409 .addReg(AArch64::X2)
410 .addReg(AArch64::SP)
411 .addImm(2));
412 EmitToStreamer(O, MovX0Op0);
413 EmitToStreamer(O, MovX1Op1);
414 EmitToStreamer(O, MCInstBuilder(AArch64::ORRXrs)
415 .addReg(AArch64::X2)
416 .addReg(AArch64::XZR)
417 .addReg(MI.getOperand(2).getReg())
418 .addImm(0));
419 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
420 EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui)
421 .addReg(AArch64::X2)
422 .addReg(AArch64::SP)
423 .addImm(2));
424 O.AddComment("End XRay typed event");
425 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
426 .addReg(AArch64::SP)
427 .addReg(AArch64::X0)
428 .addReg(AArch64::X1)
429 .addReg(AArch64::SP)
430 .addImm(4));
431
432 recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2);
433 } else {
434 O.AddComment("Begin XRay custom event");
435 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6));
436 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
437 .addReg(AArch64::SP)
438 .addReg(AArch64::X0)
439 .addReg(AArch64::X1)
440 .addReg(AArch64::SP)
441 .addImm(-2));
442 EmitToStreamer(O, MovX0Op0);
443 EmitToStreamer(O, MovX1Op1);
444 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
445 O.AddComment("End XRay custom event");
446 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
447 .addReg(AArch64::SP)
448 .addReg(AArch64::X0)
449 .addReg(AArch64::X1)
450 .addReg(AArch64::SP)
451 .addImm(2));
452
453 recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2);
454 }
455}
456
457void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
458 Register AddrReg = MI.getOperand(0).getReg();
459 assert(std::next(MI.getIterator())->isCall() &&
460 "KCFI_CHECK not followed by a call instruction");
461 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
462 "KCFI_CHECK call target doesn't match call operand");
463
464 // Default to using the intra-procedure-call temporary registers for
465 // comparing the hashes.
466 unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
467 if (AddrReg == AArch64::XZR) {
468 // Checking XZR makes no sense. Instead of emitting a load, zero
469 // ScratchRegs[0] and use it for the ESR AddrIndex below.
470 AddrReg = getXRegFromWReg(ScratchRegs[0]);
471 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
472 .addReg(AddrReg)
473 .addReg(AArch64::XZR)
474 .addReg(AArch64::XZR)
475 .addImm(0));
476 } else {
477 // If one of the scratch registers is used for the call target (e.g.
478 // with AArch64::TCRETURNriBTI), we can clobber another caller-saved
479 // temporary register instead (in this case, AArch64::W9) as the check
480 // is immediately followed by the call instruction.
481 for (auto &Reg : ScratchRegs) {
482 if (Reg == getWRegFromXReg(AddrReg)) {
483 Reg = AArch64::W9;
484 break;
485 }
486 }
487 assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
488 "Invalid scratch registers for KCFI_CHECK");
489
490 // Adjust the offset for patchable-function-prefix. This assumes that
491 // patchable-function-prefix is the same for all functions.
492 int64_t PrefixNops = 0;
493 (void)MI.getMF()
494 ->getFunction()
495 .getFnAttribute("patchable-function-prefix")
496 .getValueAsString()
497 .getAsInteger(10, PrefixNops);
498
499 // Load the target function type hash.
500 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
501 .addReg(ScratchRegs[0])
502 .addReg(AddrReg)
503 .addImm(-(PrefixNops * 4 + 4)));
504 }
505
506 // Load the expected type hash.
507 const int64_t Type = MI.getOperand(1).getImm();
508 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
509 .addReg(ScratchRegs[1])
510 .addReg(ScratchRegs[1])
511 .addImm(Type & 0xFFFF)
512 .addImm(0));
513 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
514 .addReg(ScratchRegs[1])
515 .addReg(ScratchRegs[1])
516 .addImm((Type >> 16) & 0xFFFF)
517 .addImm(16));
518
519 // Compare the hashes and trap if there's a mismatch.
520 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs)
521 .addReg(AArch64::WZR)
522 .addReg(ScratchRegs[0])
523 .addReg(ScratchRegs[1])
524 .addImm(0));
525
526 MCSymbol *Pass = OutContext.createTempSymbol();
527 EmitToStreamer(*OutStreamer,
528 MCInstBuilder(AArch64::Bcc)
529 .addImm(AArch64CC::EQ)
530 .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
531
532 // The base ESR is 0x8000 and the register information is encoded in bits
533 // 0-9 as follows:
534 // - 0-4: n, where the register Xn contains the target address
535 // - 5-9: m, where the register Wm contains the expected type hash
536 // Where n, m are in [0, 30].
537 unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
538 unsigned AddrIndex;
539 switch (AddrReg) {
540 default:
541 AddrIndex = AddrReg - AArch64::X0;
542 break;
543 case AArch64::FP:
544 AddrIndex = 29;
545 break;
546 case AArch64::LR:
547 AddrIndex = 30;
548 break;
549 }
550
551 assert(AddrIndex < 31 && TypeIndex < 31);
552
553 unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
554 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR));
555 OutStreamer->emitLabel(Pass);
556}
557
558void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
559 Register Reg = MI.getOperand(0).getReg();
560 bool IsShort =
561 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
562 (MI.getOpcode() ==
563 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
564 uint32_t AccessInfo = MI.getOperand(1).getImm();
565 bool IsFixedShadow =
566 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
567 (MI.getOpcode() ==
568 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
569 uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0;
570
571 MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
572 Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
573 if (!Sym) {
574 // FIXME: Make this work on non-ELF.
575 if (!TM.getTargetTriple().isOSBinFormatELF())
576 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
577
578 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
579 utostr(AccessInfo);
580 if (IsFixedShadow)
581 SymName += "_fixed_" + utostr(FixedShadowOffset);
582 if (IsShort)
583 SymName += "_short_v2";
584 Sym = OutContext.getOrCreateSymbol(SymName);
585 }
586
587 EmitToStreamer(*OutStreamer,
588 MCInstBuilder(AArch64::BL)
589 .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
590}
591
592void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
593 if (HwasanMemaccessSymbols.empty())
594 return;
595
596 const Triple &TT = TM.getTargetTriple();
597 assert(TT.isOSBinFormatELF());
598 std::unique_ptr<MCSubtargetInfo> STI(
599 TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
600 assert(STI && "Unable to create subtarget info");
601
602 MCSymbol *HwasanTagMismatchV1Sym =
603 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
604 MCSymbol *HwasanTagMismatchV2Sym =
605 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
606
607 const MCSymbolRefExpr *HwasanTagMismatchV1Ref =
608 MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext);
609 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
610 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
611
612 for (auto &P : HwasanMemaccessSymbols) {
613 unsigned Reg = std::get<0>(P.first);
614 bool IsShort = std::get<1>(P.first);
615 uint32_t AccessInfo = std::get<2>(P.first);
616 bool IsFixedShadow = std::get<3>(P.first);
617 uint64_t FixedShadowOffset = std::get<4>(P.first);
618 const MCSymbolRefExpr *HwasanTagMismatchRef =
619 IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
620 MCSymbol *Sym = P.second;
621
622 bool HasMatchAllTag =
623 (AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1;
624 uint8_t MatchAllTag =
625 (AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff;
626 unsigned Size =
627 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
628 bool CompileKernel =
629 (AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1;
630
631 OutStreamer->switchSection(OutContext.getELFSection(
632 ".text.hot", ELF::SHT_PROGBITS,
634 /*IsComdat=*/true));
635
636 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
637 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
638 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
639 OutStreamer->emitLabel(Sym);
640
641 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SBFMXri)
642 .addReg(AArch64::X16)
643 .addReg(Reg)
644 .addImm(4)
645 .addImm(55),
646 *STI);
647
648 if (IsFixedShadow) {
649 // Aarch64 makes it difficult to embed large constants in the code.
650 // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit
651 // left-shift option in the MOV instruction. Combined with the 16-bit
652 // immediate, this is enough to represent any offset up to 2**48.
653 OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
654 .addReg(AArch64::X17)
655 .addImm(FixedShadowOffset >> 32)
656 .addImm(32),
657 *STI);
658 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX)
659 .addReg(AArch64::W16)
660 .addReg(AArch64::X17)
661 .addReg(AArch64::X16)
662 .addImm(0)
663 .addImm(0),
664 *STI);
665 } else {
666 OutStreamer->emitInstruction(
667 MCInstBuilder(AArch64::LDRBBroX)
668 .addReg(AArch64::W16)
669 .addReg(IsShort ? AArch64::X20 : AArch64::X9)
670 .addReg(AArch64::X16)
671 .addImm(0)
672 .addImm(0),
673 *STI);
674 }
675
676 OutStreamer->emitInstruction(
677 MCInstBuilder(AArch64::SUBSXrs)
678 .addReg(AArch64::XZR)
679 .addReg(AArch64::X16)
680 .addReg(Reg)
682 *STI);
683 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
684 OutStreamer->emitInstruction(
685 MCInstBuilder(AArch64::Bcc)
687 .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
688 OutContext)),
689 *STI);
690 MCSymbol *ReturnSym = OutContext.createTempSymbol();
691 OutStreamer->emitLabel(ReturnSym);
692 OutStreamer->emitInstruction(
693 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
694 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
695
696 if (HasMatchAllTag) {
697 OutStreamer->emitInstruction(MCInstBuilder(AArch64::UBFMXri)
698 .addReg(AArch64::X17)
699 .addReg(Reg)
700 .addImm(56)
701 .addImm(63),
702 *STI);
703 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSXri)
704 .addReg(AArch64::XZR)
705 .addReg(AArch64::X17)
706 .addImm(MatchAllTag)
707 .addImm(0),
708 *STI);
709 OutStreamer->emitInstruction(
710 MCInstBuilder(AArch64::Bcc)
712 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
713 *STI);
714 }
715
716 if (IsShort) {
717 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWri)
718 .addReg(AArch64::WZR)
719 .addReg(AArch64::W16)
720 .addImm(15)
721 .addImm(0),
722 *STI);
723 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
724 OutStreamer->emitInstruction(
725 MCInstBuilder(AArch64::Bcc)
727 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
728 *STI);
729
730 OutStreamer->emitInstruction(
731 MCInstBuilder(AArch64::ANDXri)
732 .addReg(AArch64::X17)
733 .addReg(Reg)
735 *STI);
736 if (Size != 1)
737 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
738 .addReg(AArch64::X17)
739 .addReg(AArch64::X17)
740 .addImm(Size - 1)
741 .addImm(0),
742 *STI);
743 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWrs)
744 .addReg(AArch64::WZR)
745 .addReg(AArch64::W16)
746 .addReg(AArch64::W17)
747 .addImm(0),
748 *STI);
749 OutStreamer->emitInstruction(
750 MCInstBuilder(AArch64::Bcc)
752 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
753 *STI);
754
755 OutStreamer->emitInstruction(
756 MCInstBuilder(AArch64::ORRXri)
757 .addReg(AArch64::X16)
758 .addReg(Reg)
760 *STI);
761 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBui)
762 .addReg(AArch64::W16)
763 .addReg(AArch64::X16)
764 .addImm(0),
765 *STI);
766 OutStreamer->emitInstruction(
767 MCInstBuilder(AArch64::SUBSXrs)
768 .addReg(AArch64::XZR)
769 .addReg(AArch64::X16)
770 .addReg(Reg)
772 *STI);
773 OutStreamer->emitInstruction(
774 MCInstBuilder(AArch64::Bcc)
776 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
777 *STI);
778
779 OutStreamer->emitLabel(HandleMismatchSym);
780 }
781
782 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
783 .addReg(AArch64::SP)
784 .addReg(AArch64::X0)
785 .addReg(AArch64::X1)
786 .addReg(AArch64::SP)
787 .addImm(-32),
788 *STI);
789 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
790 .addReg(AArch64::FP)
791 .addReg(AArch64::LR)
792 .addReg(AArch64::SP)
793 .addImm(29),
794 *STI);
795
796 if (Reg != AArch64::X0)
797 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ORRXrs)
798 .addReg(AArch64::X0)
799 .addReg(AArch64::XZR)
800 .addReg(Reg)
801 .addImm(0),
802 *STI);
803 OutStreamer->emitInstruction(
804 MCInstBuilder(AArch64::MOVZXi)
805 .addReg(AArch64::X1)
807 .addImm(0),
808 *STI);
809
810 if (CompileKernel) {
811 // The Linux kernel's dynamic loader doesn't support GOT relative
812 // relocations, but it doesn't support late binding either, so just call
813 // the function directly.
814 OutStreamer->emitInstruction(
815 MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef), *STI);
816 } else {
817 // Intentionally load the GOT entry and branch to it, rather than possibly
818 // late binding the function, which may clobber the registers before we
819 // have a chance to save them.
820 OutStreamer->emitInstruction(
821 MCInstBuilder(AArch64::ADRP)
822 .addReg(AArch64::X16)
824 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_PAGE,
825 OutContext)),
826 *STI);
827 OutStreamer->emitInstruction(
828 MCInstBuilder(AArch64::LDRXui)
829 .addReg(AArch64::X16)
830 .addReg(AArch64::X16)
832 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_LO12,
833 OutContext)),
834 *STI);
835 OutStreamer->emitInstruction(
836 MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI);
837 }
838 }
839}
840
841void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
842 emitHwasanMemaccessSymbols(M);
843
844 const Triple &TT = TM.getTargetTriple();
845 if (TT.isOSBinFormatMachO()) {
846 // Funny Darwin hack: This flag tells the linker that no global symbols
847 // contain code that falls through to other global symbols (e.g. the obvious
848 // implementation of multiple entry points). If this doesn't occur, the
849 // linker can safely perform dead code stripping. Since LLVM never
850 // generates code that does this, it is always safe to set.
851 OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols);
852 }
853
854 // Emit stack and fault map information.
855 FM.serializeToFaultMapSection();
856
857}
858
859void AArch64AsmPrinter::emitLOHs() {
861
862 for (const auto &D : AArch64FI->getLOHContainer()) {
863 for (const MachineInstr *MI : D.getArgs()) {
864 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
865 assert(LabelIt != LOHInstToLabel.end() &&
866 "Label hasn't been inserted for LOH related instruction");
867 MCArgs.push_back(LabelIt->second);
868 }
869 OutStreamer->emitLOHDirective(D.getKind(), MCArgs);
870 MCArgs.clear();
871 }
872}
873
874void AArch64AsmPrinter::emitFunctionBodyEnd() {
875 if (!AArch64FI->getLOHRelated().empty())
876 emitLOHs();
877}
878
879/// GetCPISymbol - Return the symbol for the specified constant pool entry.
880MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
881 // Darwin uses a linker-private symbol name for constant-pools (to
882 // avoid addends on the relocation?), ELF has no such concept and
883 // uses a normal private symbol.
884 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
885 return OutContext.getOrCreateSymbol(
886 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
887 Twine(getFunctionNumber()) + "_" + Twine(CPID));
888
889 return AsmPrinter::GetCPISymbol(CPID);
890}
891
892void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
893 raw_ostream &O) {
894 const MachineOperand &MO = MI->getOperand(OpNum);
895 switch (MO.getType()) {
896 default:
897 llvm_unreachable("<unknown operand type>");
899 Register Reg = MO.getReg();
900 assert(Reg.isPhysical());
901 assert(!MO.getSubReg() && "Subregs should be eliminated!");
903 break;
904 }
906 O << MO.getImm();
907 break;
908 }
910 PrintSymbolOperand(MO, O);
911 break;
912 }
914 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
915 Sym->print(O, MAI);
916 break;
917 }
918 }
919}
920
921bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
922 raw_ostream &O) {
923 Register Reg = MO.getReg();
924 switch (Mode) {
925 default:
926 return true; // Unknown mode.
927 case 'w':
928 Reg = getWRegFromXReg(Reg);
929 break;
930 case 'x':
931 Reg = getXRegFromWReg(Reg);
932 break;
933 case 't':
935 break;
936 }
937
939 return false;
940}
941
942// Prints the register in MO using class RC using the offset in the
943// new register class. This should not be used for cross class
944// printing.
945bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
946 const TargetRegisterClass *RC,
947 unsigned AltName, raw_ostream &O) {
948 assert(MO.isReg() && "Should only get here with a register!");
949 const TargetRegisterInfo *RI = STI->getRegisterInfo();
950 Register Reg = MO.getReg();
951 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
952 if (!RI->regsOverlap(RegToPrint, Reg))
953 return true;
954 O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName);
955 return false;
956}
957
958bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
959 const char *ExtraCode, raw_ostream &O) {
960 const MachineOperand &MO = MI->getOperand(OpNum);
961
962 // First try the generic code, which knows about modifiers like 'c' and 'n'.
963 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
964 return false;
965
966 // Does this asm operand have a single letter operand modifier?
967 if (ExtraCode && ExtraCode[0]) {
968 if (ExtraCode[1] != 0)
969 return true; // Unknown modifier.
970
971 switch (ExtraCode[0]) {
972 default:
973 return true; // Unknown modifier.
974 case 'w': // Print W register
975 case 'x': // Print X register
976 if (MO.isReg())
977 return printAsmMRegister(MO, ExtraCode[0], O);
978 if (MO.isImm() && MO.getImm() == 0) {
979 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
981 return false;
982 }
983 printOperand(MI, OpNum, O);
984 return false;
985 case 'b': // Print B register.
986 case 'h': // Print H register.
987 case 's': // Print S register.
988 case 'd': // Print D register.
989 case 'q': // Print Q register.
990 case 'z': // Print Z register.
991 if (MO.isReg()) {
992 const TargetRegisterClass *RC;
993 switch (ExtraCode[0]) {
994 case 'b':
995 RC = &AArch64::FPR8RegClass;
996 break;
997 case 'h':
998 RC = &AArch64::FPR16RegClass;
999 break;
1000 case 's':
1001 RC = &AArch64::FPR32RegClass;
1002 break;
1003 case 'd':
1004 RC = &AArch64::FPR64RegClass;
1005 break;
1006 case 'q':
1007 RC = &AArch64::FPR128RegClass;
1008 break;
1009 case 'z':
1010 RC = &AArch64::ZPRRegClass;
1011 break;
1012 default:
1013 return true;
1014 }
1015 return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
1016 }
1017 printOperand(MI, OpNum, O);
1018 return false;
1019 }
1020 }
1021
1022 // According to ARM, we should emit x and v registers unless we have a
1023 // modifier.
1024 if (MO.isReg()) {
1025 Register Reg = MO.getReg();
1026
1027 // If this is a w or x register, print an x register.
1028 if (AArch64::GPR32allRegClass.contains(Reg) ||
1029 AArch64::GPR64allRegClass.contains(Reg))
1030 return printAsmMRegister(MO, 'x', O);
1031
1032 // If this is an x register tuple, print an x register.
1033 if (AArch64::GPR64x8ClassRegClass.contains(Reg))
1034 return printAsmMRegister(MO, 't', O);
1035
1036 unsigned AltName = AArch64::NoRegAltName;
1037 const TargetRegisterClass *RegClass;
1038 if (AArch64::ZPRRegClass.contains(Reg)) {
1039 RegClass = &AArch64::ZPRRegClass;
1040 } else if (AArch64::PPRRegClass.contains(Reg)) {
1041 RegClass = &AArch64::PPRRegClass;
1042 } else if (AArch64::PNRRegClass.contains(Reg)) {
1043 RegClass = &AArch64::PNRRegClass;
1044 } else {
1045 RegClass = &AArch64::FPR128RegClass;
1046 AltName = AArch64::vreg;
1047 }
1048
1049 // If this is a b, h, s, d, or q register, print it as a v register.
1050 return printAsmRegInClass(MO, RegClass, AltName, O);
1051 }
1052
1053 printOperand(MI, OpNum, O);
1054 return false;
1055}
1056
1057bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1058 unsigned OpNum,
1059 const char *ExtraCode,
1060 raw_ostream &O) {
1061 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
1062 return true; // Unknown modifier.
1063
1064 const MachineOperand &MO = MI->getOperand(OpNum);
1065 assert(MO.isReg() && "unexpected inline asm memory operand");
1066 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
1067 return false;
1068}
1069
1070void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
1071 raw_ostream &OS) {
1072 unsigned NOps = MI->getNumOperands();
1073 assert(NOps == 4);
1074 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
1075 // cast away const; DIetc do not take const operands for some reason.
1076 OS << MI->getDebugVariable()->getName();
1077 OS << " <- ";
1078 // Frame address. Currently handles register +- offset only.
1079 assert(MI->isIndirectDebugValue());
1080 OS << '[';
1081 for (unsigned I = 0, E = std::distance(MI->debug_operands().begin(),
1082 MI->debug_operands().end());
1083 I < E; ++I) {
1084 if (I != 0)
1085 OS << ", ";
1086 printOperand(MI, I, OS);
1087 }
1088 OS << ']';
1089 OS << "+";
1090 printOperand(MI, NOps - 2, OS);
1091}
1092
1093void AArch64AsmPrinter::emitJumpTableInfo() {
1094 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
1095 if (!MJTI) return;
1096
1097 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
1098 if (JT.empty()) return;
1099
1100 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1101 MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(MF->getFunction(), TM);
1102 OutStreamer->switchSection(ReadOnlySec);
1103
1104 auto AFI = MF->getInfo<AArch64FunctionInfo>();
1105 for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
1106 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
1107
1108 // If this jump table was deleted, ignore it.
1109 if (JTBBs.empty()) continue;
1110
1111 unsigned Size = AFI->getJumpTableEntrySize(JTI);
1112 emitAlignment(Align(Size));
1113 OutStreamer->emitLabel(GetJTISymbol(JTI));
1114
1115 const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1116 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
1117
1118 for (auto *JTBB : JTBBs) {
1119 const MCExpr *Value =
1120 MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext);
1121
1122 // Each entry is:
1123 // .byte/.hword (LBB - Lbase)>>2
1124 // or plain:
1125 // .word LBB - Lbase
1126 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
1127 if (Size != 4)
1129 Value, MCConstantExpr::create(2, OutContext), OutContext);
1130
1131 OutStreamer->emitValue(Value, Size);
1132 }
1133 }
1134}
1135
1136std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
1138AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI,
1139 const MachineInstr *BranchInstr,
1140 const MCSymbol *BranchLabel) const {
1141 const auto AFI = MF->getInfo<AArch64FunctionInfo>();
1142 const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1144 switch (AFI->getJumpTableEntrySize(JTI)) {
1145 case 1:
1146 EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
1147 break;
1148 case 2:
1149 EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
1150 break;
1151 case 4:
1152 EntrySize = codeview::JumpTableEntrySize::Int32;
1153 break;
1154 default:
1155 llvm_unreachable("Unexpected jump table entry size");
1156 }
1157 return std::make_tuple(Base, 0, BranchLabel, EntrySize);
1158}
1159
1160void AArch64AsmPrinter::emitFunctionEntryLabel() {
1161 if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
1162 MF->getFunction().getCallingConv() ==
1164 MF->getInfo<AArch64FunctionInfo>()->isSVECC()) {
1165 auto *TS =
1166 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1167 TS->emitDirectiveVariantPCS(CurrentFnSym);
1168 }
1169
1171
1172 if (TM.getTargetTriple().isWindowsArm64EC() &&
1173 !MF->getFunction().hasLocalLinkage()) {
1174 // For ARM64EC targets, a function definition's name is mangled differently
1175 // from the normal symbol, emit required aliases here.
1176 auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) {
1177 OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep);
1178 OutStreamer->emitAssignment(
1180 MMI->getContext()));
1181 };
1182
1183 auto getSymbolFromMetadata = [&](StringRef Name) {
1184 MCSymbol *Sym = nullptr;
1185 if (MDNode *Node = MF->getFunction().getMetadata(Name)) {
1186 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1187 Sym = MMI->getContext().getOrCreateSymbol(NameStr);
1188 }
1189 return Sym;
1190 };
1191
1192 if (MCSymbol *UnmangledSym =
1193 getSymbolFromMetadata("arm64ec_unmangled_name")) {
1194 MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name");
1195
1196 if (ECMangledSym) {
1197 // An external function, emit the alias from the unmangled symbol to
1198 // mangled symbol name and the alias from the mangled symbol to guest
1199 // exit thunk.
1200 emitFunctionAlias(UnmangledSym, ECMangledSym);
1201 emitFunctionAlias(ECMangledSym, CurrentFnSym);
1202 } else {
1203 // A function implementation, emit the alias from the unmangled symbol
1204 // to mangled symbol name.
1205 emitFunctionAlias(UnmangledSym, CurrentFnSym);
1206 }
1207 }
1208 }
1209}
1210
1211/// Small jump tables contain an unsigned byte or half, representing the offset
1212/// from the lowest-addressed possible destination to the desired basic
1213/// block. Since all instructions are 4-byte aligned, this is further compressed
1214/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
1215/// materialize the correct destination we need:
1216///
1217/// adr xDest, .LBB0_0
1218/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
1219/// add xDest, xDest, xScratch (with "lsl #2" for smaller entries)
1220void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer,
1221 const llvm::MachineInstr &MI) {
1222 Register DestReg = MI.getOperand(0).getReg();
1223 Register ScratchReg = MI.getOperand(1).getReg();
1224 Register ScratchRegW =
1225 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
1226 Register TableReg = MI.getOperand(2).getReg();
1227 Register EntryReg = MI.getOperand(3).getReg();
1228 int JTIdx = MI.getOperand(4).getIndex();
1229 int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
1230
1231 // This has to be first because the compression pass based its reachability
1232 // calculations on the start of the JumpTableDest instruction.
1233 auto Label =
1234 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
1235
1236 // If we don't already have a symbol to use as the base, use the ADR
1237 // instruction itself.
1238 if (!Label) {
1239 Label = MF->getContext().createTempSymbol();
1240 AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label);
1241 OutStreamer.emitLabel(Label);
1242 }
1243
1244 auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext());
1245 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
1246 .addReg(DestReg)
1247 .addExpr(LabelExpr));
1248
1249 // Load the number of instruction-steps to offset from the label.
1250 unsigned LdrOpcode;
1251 switch (Size) {
1252 case 1: LdrOpcode = AArch64::LDRBBroX; break;
1253 case 2: LdrOpcode = AArch64::LDRHHroX; break;
1254 case 4: LdrOpcode = AArch64::LDRSWroX; break;
1255 default:
1256 llvm_unreachable("Unknown jump table size");
1257 }
1258
1259 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
1260 .addReg(Size == 4 ? ScratchReg : ScratchRegW)
1261 .addReg(TableReg)
1262 .addReg(EntryReg)
1263 .addImm(0)
1264 .addImm(Size == 1 ? 0 : 1));
1265
1266 // Add to the already materialized base label address, multiplying by 4 if
1267 // compressed.
1268 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1269 .addReg(DestReg)
1270 .addReg(DestReg)
1271 .addReg(ScratchReg)
1272 .addImm(Size == 4 ? 0 : 2));
1273}
1274
1275void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer,
1276 const llvm::MachineInstr &MI) {
1277 unsigned Opcode = MI.getOpcode();
1278 assert(STI->hasMOPS());
1279 assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
1280
1281 const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
1282 if (Opcode == AArch64::MOPSMemoryCopyPseudo)
1283 return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
1284 if (Opcode == AArch64::MOPSMemoryMovePseudo)
1285 return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
1286 if (Opcode == AArch64::MOPSMemorySetPseudo)
1287 return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
1288 if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
1289 return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
1290 llvm_unreachable("Unhandled memory operation pseudo");
1291 }();
1292 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
1293 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
1294
1295 for (auto Op : Ops) {
1296 int i = 0;
1297 auto MCIB = MCInstBuilder(Op);
1298 // Destination registers
1299 MCIB.addReg(MI.getOperand(i++).getReg());
1300 MCIB.addReg(MI.getOperand(i++).getReg());
1301 if (!IsSet)
1302 MCIB.addReg(MI.getOperand(i++).getReg());
1303 // Input registers
1304 MCIB.addReg(MI.getOperand(i++).getReg());
1305 MCIB.addReg(MI.getOperand(i++).getReg());
1306 MCIB.addReg(MI.getOperand(i++).getReg());
1307
1308 EmitToStreamer(OutStreamer, MCIB);
1309 }
1310}
1311
1312void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1313 const MachineInstr &MI) {
1314 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
1315
1316 auto &Ctx = OutStreamer.getContext();
1317 MCSymbol *MILabel = Ctx.createTempSymbol();
1318 OutStreamer.emitLabel(MILabel);
1319
1320 SM.recordStackMap(*MILabel, MI);
1321 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1322
1323 // Scan ahead to trim the shadow.
1324 const MachineBasicBlock &MBB = *MI.getParent();
1326 ++MII;
1327 while (NumNOPBytes > 0) {
1328 if (MII == MBB.end() || MII->isCall() ||
1329 MII->getOpcode() == AArch64::DBG_VALUE ||
1330 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1331 MII->getOpcode() == TargetOpcode::STACKMAP)
1332 break;
1333 ++MII;
1334 NumNOPBytes -= 4;
1335 }
1336
1337 // Emit nops.
1338 for (unsigned i = 0; i < NumNOPBytes; i += 4)
1339 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1340}
1341
1342// Lower a patchpoint of the form:
1343// [<def>], <id>, <numBytes>, <target>, <numArgs>
1344void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1345 const MachineInstr &MI) {
1346 auto &Ctx = OutStreamer.getContext();
1347 MCSymbol *MILabel = Ctx.createTempSymbol();
1348 OutStreamer.emitLabel(MILabel);
1349 SM.recordPatchPoint(*MILabel, MI);
1350
1351 PatchPointOpers Opers(&MI);
1352
1353 int64_t CallTarget = Opers.getCallTarget().getImm();
1354 unsigned EncodedBytes = 0;
1355 if (CallTarget) {
1356 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
1357 "High 16 bits of call target should be zero.");
1358 Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
1359 EncodedBytes = 16;
1360 // Materialize the jump address:
1361 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1362 .addReg(ScratchReg)
1363 .addImm((CallTarget >> 32) & 0xFFFF)
1364 .addImm(32));
1365 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1366 .addReg(ScratchReg)
1367 .addReg(ScratchReg)
1368 .addImm((CallTarget >> 16) & 0xFFFF)
1369 .addImm(16));
1370 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1371 .addReg(ScratchReg)
1372 .addReg(ScratchReg)
1373 .addImm(CallTarget & 0xFFFF)
1374 .addImm(0));
1375 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
1376 }
1377 // Emit padding.
1378 unsigned NumBytes = Opers.getNumPatchBytes();
1379 assert(NumBytes >= EncodedBytes &&
1380 "Patchpoint can't request size less than the length of a call.");
1381 assert((NumBytes - EncodedBytes) % 4 == 0 &&
1382 "Invalid number of NOP bytes requested!");
1383 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
1384 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1385}
1386
1387void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1388 const MachineInstr &MI) {
1389 StatepointOpers SOpers(&MI);
1390 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1391 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1392 for (unsigned i = 0; i < PatchBytes; i += 4)
1393 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1394 } else {
1395 // Lower call target and choose correct opcode
1396 const MachineOperand &CallTarget = SOpers.getCallTarget();
1397 MCOperand CallTargetMCOp;
1398 unsigned CallOpcode;
1399 switch (CallTarget.getType()) {
1402 MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1403 CallOpcode = AArch64::BL;
1404 break;
1406 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
1407 CallOpcode = AArch64::BL;
1408 break;
1410 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
1411 CallOpcode = AArch64::BLR;
1412 break;
1413 default:
1414 llvm_unreachable("Unsupported operand type in statepoint call target");
1415 break;
1416 }
1417
1418 EmitToStreamer(OutStreamer,
1419 MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
1420 }
1421
1422 auto &Ctx = OutStreamer.getContext();
1423 MCSymbol *MILabel = Ctx.createTempSymbol();
1424 OutStreamer.emitLabel(MILabel);
1425 SM.recordStatepoint(*MILabel, MI);
1426}
1427
1428void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) {
1429 // FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>,
1430 // <opcode>, <operands>
1431
1432 Register DefRegister = FaultingMI.getOperand(0).getReg();
1434 static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm());
1435 MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol();
1436 unsigned Opcode = FaultingMI.getOperand(3).getImm();
1437 unsigned OperandsBeginIdx = 4;
1438
1439 auto &Ctx = OutStreamer->getContext();
1440 MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1441 OutStreamer->emitLabel(FaultingLabel);
1442
1443 assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!");
1444 FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1445
1446 MCInst MI;
1447 MI.setOpcode(Opcode);
1448
1449 if (DefRegister != (Register)0)
1450 MI.addOperand(MCOperand::createReg(DefRegister));
1451
1452 for (const MachineOperand &MO :
1453 llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) {
1454 MCOperand Dest;
1455 lowerOperand(MO, Dest);
1456 MI.addOperand(Dest);
1457 }
1458
1459 OutStreamer->AddComment("on-fault: " + HandlerLabel->getName());
1460 OutStreamer->emitInstruction(MI, getSubtargetInfo());
1461}
1462
1463void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
1464 Register DestReg = MI.getOperand(0).getReg();
1465 if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() &&
1466 STI->isNeonAvailable()) {
1467 // Convert H/S register to corresponding D register
1468 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
1469 DestReg = AArch64::D0 + (DestReg - AArch64::H0);
1470 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
1471 DestReg = AArch64::D0 + (DestReg - AArch64::S0);
1472 else
1473 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
1474
1475 MCInst MOVI;
1476 MOVI.setOpcode(AArch64::MOVID);
1477 MOVI.addOperand(MCOperand::createReg(DestReg));
1478 MOVI.addOperand(MCOperand::createImm(0));
1479 EmitToStreamer(*OutStreamer, MOVI);
1480 } else {
1481 MCInst FMov;
1482 switch (MI.getOpcode()) {
1483 default: llvm_unreachable("Unexpected opcode");
1484 case AArch64::FMOVH0:
1485 FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
1486 if (!STI->hasFullFP16())
1487 DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
1488 FMov.addOperand(MCOperand::createReg(DestReg));
1489 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
1490 break;
1491 case AArch64::FMOVS0:
1492 FMov.setOpcode(AArch64::FMOVWSr);
1493 FMov.addOperand(MCOperand::createReg(DestReg));
1494 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
1495 break;
1496 case AArch64::FMOVD0:
1497 FMov.setOpcode(AArch64::FMOVXDr);
1498 FMov.addOperand(MCOperand::createReg(DestReg));
1499 FMov.addOperand(MCOperand::createReg(AArch64::XZR));
1500 break;
1501 }
1502 EmitToStreamer(*OutStreamer, FMov);
1503 }
1504}
1505
1506unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
1507 unsigned AddrDisc,
1508 unsigned &InstsEmitted) {
1509 // So far we've used NoRegister in pseudos. Now we need real encodings.
1510 if (AddrDisc == AArch64::NoRegister)
1511 AddrDisc = AArch64::XZR;
1512
1513 // If there is no constant discriminator, there's no blend involved:
1514 // just use the address discriminator register as-is (XZR or not).
1515 if (!Disc)
1516 return AddrDisc;
1517
1518 // If there's only a constant discriminator, MOV it into x17.
1519 if (AddrDisc == AArch64::XZR) {
1520 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1521 .addReg(AArch64::X17)
1522 .addImm(Disc)
1523 .addImm(/*shift=*/0));
1524 ++InstsEmitted;
1525 return AArch64::X17;
1526 }
1527
1528 // If there are both, emit a blend into x17.
1529 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1530 .addReg(AArch64::X17)
1531 .addReg(AArch64::XZR)
1532 .addReg(AddrDisc)
1533 .addImm(0));
1534 ++InstsEmitted;
1535 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1536 .addReg(AArch64::X17)
1537 .addReg(AArch64::X17)
1538 .addImm(Disc)
1539 .addImm(/*shift=*/48));
1540 ++InstsEmitted;
1541 return AArch64::X17;
1542}
1543
1544void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
1545 unsigned InstsEmitted = 0;
1546 unsigned BrTarget = MI->getOperand(0).getReg();
1547
1548 auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm();
1549 assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
1550 "Invalid auth call key");
1551
1552 uint64_t Disc = MI->getOperand(2).getImm();
1553 assert(isUInt<16>(Disc));
1554
1555 unsigned AddrDisc = MI->getOperand(3).getReg();
1556
1557 // Compute discriminator into x17
1558 unsigned DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, InstsEmitted);
1559 bool IsZeroDisc = DiscReg == AArch64::XZR;
1560
1561 unsigned Opc;
1562 if (Key == AArch64PACKey::IA)
1563 Opc = IsZeroDisc ? AArch64::BLRAAZ : AArch64::BLRAA;
1564 else
1565 Opc = IsZeroDisc ? AArch64::BLRABZ : AArch64::BLRAB;
1566
1567 MCInst BRInst;
1568 BRInst.setOpcode(Opc);
1569 BRInst.addOperand(MCOperand::createReg(BrTarget));
1570 if (!IsZeroDisc)
1571 BRInst.addOperand(MCOperand::createReg(DiscReg));
1572 EmitToStreamer(*OutStreamer, BRInst);
1573 ++InstsEmitted;
1574
1575 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
1576}
1577
1578// Simple pseudo-instructions have their lowering (with expansion to real
1579// instructions) auto-generated.
1580#include "AArch64GenMCPseudoLowering.inc"
1581
1582void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
1583 AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
1584
1585 // Do any auto-generated pseudo lowerings.
1586 if (emitPseudoExpansionLowering(*OutStreamer, MI))
1587 return;
1588
1589 if (MI->getOpcode() == AArch64::ADRP) {
1590 for (auto &Opd : MI->operands()) {
1591 if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) ==
1592 "swift_async_extendedFramePointerFlags") {
1593 ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true;
1594 }
1595 }
1596 }
1597
1598 if (AArch64FI->getLOHRelated().count(MI)) {
1599 // Generate a label for LOH related instruction
1600 MCSymbol *LOHLabel = createTempSymbol("loh");
1601 // Associate the instruction with the label
1602 LOHInstToLabel[MI] = LOHLabel;
1603 OutStreamer->emitLabel(LOHLabel);
1604 }
1605
1607 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1608 // Do any manual lowerings.
1609 switch (MI->getOpcode()) {
1610 default:
1611 break;
1612 case AArch64::HINT: {
1613 // CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for
1614 // -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be
1615 // non-empty. If MI is the initial BTI, place the
1616 // __patchable_function_entries label after BTI.
1617 if (CurrentPatchableFunctionEntrySym &&
1618 CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
1619 MI == &MF->front().front()) {
1620 int64_t Imm = MI->getOperand(0).getImm();
1621 if ((Imm & 32) && (Imm & 6)) {
1622 MCInst Inst;
1623 MCInstLowering.Lower(MI, Inst);
1624 EmitToStreamer(*OutStreamer, Inst);
1625 CurrentPatchableFunctionEntrySym = createTempSymbol("patch");
1626 OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym);
1627 return;
1628 }
1629 }
1630 break;
1631 }
1632 case AArch64::MOVMCSym: {
1633 Register DestReg = MI->getOperand(0).getReg();
1634 const MachineOperand &MO_Sym = MI->getOperand(1);
1635 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
1636 MCOperand Hi_MCSym, Lo_MCSym;
1637
1638 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
1639 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
1640
1641 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
1642 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
1643
1644 MCInst MovZ;
1645 MovZ.setOpcode(AArch64::MOVZXi);
1646 MovZ.addOperand(MCOperand::createReg(DestReg));
1647 MovZ.addOperand(Hi_MCSym);
1649 EmitToStreamer(*OutStreamer, MovZ);
1650
1651 MCInst MovK;
1652 MovK.setOpcode(AArch64::MOVKXi);
1653 MovK.addOperand(MCOperand::createReg(DestReg));
1654 MovK.addOperand(MCOperand::createReg(DestReg));
1655 MovK.addOperand(Lo_MCSym);
1657 EmitToStreamer(*OutStreamer, MovK);
1658 return;
1659 }
1660 case AArch64::MOVIv2d_ns:
1661 // It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0".
1662 // as movi is more efficient across all cores. Newer cores can eliminate
1663 // fmovs early and there is no difference with movi, but this not true for
1664 // all implementations.
1665 //
1666 // The floating-point version doesn't quite work in rare cases on older
1667 // CPUs, so on those targets we lower this instruction to movi.16b instead.
1668 if (STI->hasZeroCycleZeroingFPWorkaround() &&
1669 MI->getOperand(1).getImm() == 0) {
1670 MCInst TmpInst;
1671 TmpInst.setOpcode(AArch64::MOVIv16b_ns);
1672 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
1673 TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
1674 EmitToStreamer(*OutStreamer, TmpInst);
1675 return;
1676 }
1677 break;
1678
1679 case AArch64::DBG_VALUE:
1680 case AArch64::DBG_VALUE_LIST:
1681 if (isVerbose() && OutStreamer->hasRawTextSupport()) {
1682 SmallString<128> TmpStr;
1683 raw_svector_ostream OS(TmpStr);
1684 PrintDebugValueComment(MI, OS);
1685 OutStreamer->emitRawText(StringRef(OS.str()));
1686 }
1687 return;
1688
1689 case AArch64::EMITBKEY: {
1690 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
1691 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
1692 ExceptionHandlingType != ExceptionHandling::ARM)
1693 return;
1694
1695 if (getFunctionCFISectionType(*MF) == CFISection::None)
1696 return;
1697
1698 OutStreamer->emitCFIBKeyFrame();
1699 return;
1700 }
1701
1702 case AArch64::EMITMTETAGGED: {
1703 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
1704 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
1705 ExceptionHandlingType != ExceptionHandling::ARM)
1706 return;
1707
1708 if (getFunctionCFISectionType(*MF) != CFISection::None)
1709 OutStreamer->emitCFIMTETaggedFrame();
1710 return;
1711 }
1712
1713 case AArch64::BLRA:
1714 emitPtrauthBranch(MI);
1715 return;
1716
1717 // Tail calls use pseudo instructions so they have the proper code-gen
1718 // attributes (isCall, isReturn, etc.). We lower them to the real
1719 // instruction here.
1720 case AArch64::AUTH_TCRETURN:
1721 case AArch64::AUTH_TCRETURN_BTI: {
1722 const uint64_t Key = MI->getOperand(2).getImm();
1723 assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
1724 "Invalid auth key for tail-call return");
1725
1726 const uint64_t Disc = MI->getOperand(3).getImm();
1727 assert(isUInt<16>(Disc) && "Integer discriminator is too wide");
1728
1729 Register AddrDisc = MI->getOperand(4).getReg();
1730
1731 Register ScratchReg = MI->getOperand(0).getReg() == AArch64::X16
1732 ? AArch64::X17
1733 : AArch64::X16;
1734
1735 unsigned DiscReg = AddrDisc;
1736 if (Disc) {
1737 if (AddrDisc != AArch64::NoRegister) {
1738 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1739 .addReg(ScratchReg)
1740 .addReg(AArch64::XZR)
1741 .addReg(AddrDisc)
1742 .addImm(0));
1743 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
1744 .addReg(ScratchReg)
1745 .addReg(ScratchReg)
1746 .addImm(Disc)
1747 .addImm(/*shift=*/48));
1748 } else {
1749 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
1750 .addReg(ScratchReg)
1751 .addImm(Disc)
1752 .addImm(/*shift=*/0));
1753 }
1754 DiscReg = ScratchReg;
1755 }
1756
1757 const bool IsZero = DiscReg == AArch64::NoRegister;
1758 const unsigned Opcodes[2][2] = {{AArch64::BRAA, AArch64::BRAAZ},
1759 {AArch64::BRAB, AArch64::BRABZ}};
1760
1761 MCInst TmpInst;
1762 TmpInst.setOpcode(Opcodes[Key][IsZero]);
1763 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
1764 if (!IsZero)
1765 TmpInst.addOperand(MCOperand::createReg(DiscReg));
1766 EmitToStreamer(*OutStreamer, TmpInst);
1767 return;
1768 }
1769
1770 case AArch64::TCRETURNri:
1771 case AArch64::TCRETURNrix16x17:
1772 case AArch64::TCRETURNrix17:
1773 case AArch64::TCRETURNrinotx16:
1774 case AArch64::TCRETURNriALL: {
1775 MCInst TmpInst;
1776 TmpInst.setOpcode(AArch64::BR);
1777 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
1778 EmitToStreamer(*OutStreamer, TmpInst);
1779 return;
1780 }
1781 case AArch64::TCRETURNdi: {
1782 MCOperand Dest;
1783 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
1784 MCInst TmpInst;
1785 TmpInst.setOpcode(AArch64::B);
1786 TmpInst.addOperand(Dest);
1787 EmitToStreamer(*OutStreamer, TmpInst);
1788 return;
1789 }
1790 case AArch64::SpeculationBarrierISBDSBEndBB: {
1791 // Print DSB SYS + ISB
1792 MCInst TmpInstDSB;
1793 TmpInstDSB.setOpcode(AArch64::DSB);
1794 TmpInstDSB.addOperand(MCOperand::createImm(0xf));
1795 EmitToStreamer(*OutStreamer, TmpInstDSB);
1796 MCInst TmpInstISB;
1797 TmpInstISB.setOpcode(AArch64::ISB);
1798 TmpInstISB.addOperand(MCOperand::createImm(0xf));
1799 EmitToStreamer(*OutStreamer, TmpInstISB);
1800 return;
1801 }
1802 case AArch64::SpeculationBarrierSBEndBB: {
1803 // Print SB
1804 MCInst TmpInstSB;
1805 TmpInstSB.setOpcode(AArch64::SB);
1806 EmitToStreamer(*OutStreamer, TmpInstSB);
1807 return;
1808 }
1809 case AArch64::TLSDESC_CALLSEQ: {
1810 /// lower this to:
1811 /// adrp x0, :tlsdesc:var
1812 /// ldr x1, [x0, #:tlsdesc_lo12:var]
1813 /// add x0, x0, #:tlsdesc_lo12:var
1814 /// .tlsdesccall var
1815 /// blr x1
1816 /// (TPIDR_EL0 offset now in x0)
1817 const MachineOperand &MO_Sym = MI->getOperand(0);
1818 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
1819 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
1820 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
1821 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
1822 MCInstLowering.lowerOperand(MO_Sym, Sym);
1823 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
1824 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
1825
1826 MCInst Adrp;
1827 Adrp.setOpcode(AArch64::ADRP);
1828 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
1829 Adrp.addOperand(SymTLSDesc);
1830 EmitToStreamer(*OutStreamer, Adrp);
1831
1832 MCInst Ldr;
1833 if (STI->isTargetILP32()) {
1834 Ldr.setOpcode(AArch64::LDRWui);
1835 Ldr.addOperand(MCOperand::createReg(AArch64::W1));
1836 } else {
1837 Ldr.setOpcode(AArch64::LDRXui);
1838 Ldr.addOperand(MCOperand::createReg(AArch64::X1));
1839 }
1840 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
1841 Ldr.addOperand(SymTLSDescLo12);
1843 EmitToStreamer(*OutStreamer, Ldr);
1844
1845 MCInst Add;
1846 if (STI->isTargetILP32()) {
1847 Add.setOpcode(AArch64::ADDWri);
1848 Add.addOperand(MCOperand::createReg(AArch64::W0));
1849 Add.addOperand(MCOperand::createReg(AArch64::W0));
1850 } else {
1851 Add.setOpcode(AArch64::ADDXri);
1852 Add.addOperand(MCOperand::createReg(AArch64::X0));
1853 Add.addOperand(MCOperand::createReg(AArch64::X0));
1854 }
1855 Add.addOperand(SymTLSDescLo12);
1857 EmitToStreamer(*OutStreamer, Add);
1858
1859 // Emit a relocation-annotation. This expands to no code, but requests
1860 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
1861 MCInst TLSDescCall;
1862 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
1863 TLSDescCall.addOperand(Sym);
1864 EmitToStreamer(*OutStreamer, TLSDescCall);
1865
1866 MCInst Blr;
1867 Blr.setOpcode(AArch64::BLR);
1868 Blr.addOperand(MCOperand::createReg(AArch64::X1));
1869 EmitToStreamer(*OutStreamer, Blr);
1870
1871 return;
1872 }
1873
1874 case AArch64::JumpTableDest32:
1875 case AArch64::JumpTableDest16:
1876 case AArch64::JumpTableDest8:
1877 LowerJumpTableDest(*OutStreamer, *MI);
1878 return;
1879
1880 case AArch64::FMOVH0:
1881 case AArch64::FMOVS0:
1882 case AArch64::FMOVD0:
1883 emitFMov0(*MI);
1884 return;
1885
1886 case AArch64::MOPSMemoryCopyPseudo:
1887 case AArch64::MOPSMemoryMovePseudo:
1888 case AArch64::MOPSMemorySetPseudo:
1889 case AArch64::MOPSMemorySetTaggingPseudo:
1890 LowerMOPS(*OutStreamer, *MI);
1891 return;
1892
1893 case TargetOpcode::STACKMAP:
1894 return LowerSTACKMAP(*OutStreamer, SM, *MI);
1895
1896 case TargetOpcode::PATCHPOINT:
1897 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
1898
1899 case TargetOpcode::STATEPOINT:
1900 return LowerSTATEPOINT(*OutStreamer, SM, *MI);
1901
1902 case TargetOpcode::FAULTING_OP:
1903 return LowerFAULTING_OP(*MI);
1904
1905 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
1906 LowerPATCHABLE_FUNCTION_ENTER(*MI);
1907 return;
1908
1909 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
1910 LowerPATCHABLE_FUNCTION_EXIT(*MI);
1911 return;
1912
1913 case TargetOpcode::PATCHABLE_TAIL_CALL:
1914 LowerPATCHABLE_TAIL_CALL(*MI);
1915 return;
1916 case TargetOpcode::PATCHABLE_EVENT_CALL:
1917 return LowerPATCHABLE_EVENT_CALL(*MI, false);
1918 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
1919 return LowerPATCHABLE_EVENT_CALL(*MI, true);
1920
1921 case AArch64::KCFI_CHECK:
1922 LowerKCFI_CHECK(*MI);
1923 return;
1924
1925 case AArch64::HWASAN_CHECK_MEMACCESS:
1926 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
1927 case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
1928 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
1929 LowerHWASAN_CHECK_MEMACCESS(*MI);
1930 return;
1931
1932 case AArch64::SEH_StackAlloc:
1933 TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
1934 return;
1935
1936 case AArch64::SEH_SaveFPLR:
1937 TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
1938 return;
1939
1940 case AArch64::SEH_SaveFPLR_X:
1941 assert(MI->getOperand(0).getImm() < 0 &&
1942 "Pre increment SEH opcode must have a negative offset");
1943 TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
1944 return;
1945
1946 case AArch64::SEH_SaveReg:
1947 TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
1948 MI->getOperand(1).getImm());
1949 return;
1950
1951 case AArch64::SEH_SaveReg_X:
1952 assert(MI->getOperand(1).getImm() < 0 &&
1953 "Pre increment SEH opcode must have a negative offset");
1954 TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
1955 -MI->getOperand(1).getImm());
1956 return;
1957
1958 case AArch64::SEH_SaveRegP:
1959 if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 &&
1960 MI->getOperand(0).getImm() <= 28) {
1961 assert((MI->getOperand(0).getImm() - 19) % 2 == 0 &&
1962 "Register paired with LR must be odd");
1963 TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(),
1964 MI->getOperand(2).getImm());
1965 return;
1966 }
1967 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1968 "Non-consecutive registers not allowed for save_regp");
1969 TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
1970 MI->getOperand(2).getImm());
1971 return;
1972
1973 case AArch64::SEH_SaveRegP_X:
1974 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1975 "Non-consecutive registers not allowed for save_regp_x");
1976 assert(MI->getOperand(2).getImm() < 0 &&
1977 "Pre increment SEH opcode must have a negative offset");
1978 TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
1979 -MI->getOperand(2).getImm());
1980 return;
1981
1982 case AArch64::SEH_SaveFReg:
1983 TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
1984 MI->getOperand(1).getImm());
1985 return;
1986
1987 case AArch64::SEH_SaveFReg_X:
1988 assert(MI->getOperand(1).getImm() < 0 &&
1989 "Pre increment SEH opcode must have a negative offset");
1990 TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
1991 -MI->getOperand(1).getImm());
1992 return;
1993
1994 case AArch64::SEH_SaveFRegP:
1995 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1996 "Non-consecutive registers not allowed for save_regp");
1997 TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
1998 MI->getOperand(2).getImm());
1999 return;
2000
2001 case AArch64::SEH_SaveFRegP_X:
2002 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
2003 "Non-consecutive registers not allowed for save_regp_x");
2004 assert(MI->getOperand(2).getImm() < 0 &&
2005 "Pre increment SEH opcode must have a negative offset");
2006 TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
2007 -MI->getOperand(2).getImm());
2008 return;
2009
2010 case AArch64::SEH_SetFP:
2012 return;
2013
2014 case AArch64::SEH_AddFP:
2015 TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm());
2016 return;
2017
2018 case AArch64::SEH_Nop:
2019 TS->emitARM64WinCFINop();
2020 return;
2021
2022 case AArch64::SEH_PrologEnd:
2024 return;
2025
2026 case AArch64::SEH_EpilogStart:
2028 return;
2029
2030 case AArch64::SEH_EpilogEnd:
2032 return;
2033
2034 case AArch64::SEH_PACSignLR:
2036 return;
2037
2038 case AArch64::SEH_SaveAnyRegQP:
2039 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
2040 "Non-consecutive registers not allowed for save_any_reg");
2041 assert(MI->getOperand(2).getImm() >= 0 &&
2042 "SaveAnyRegQP SEH opcode offset must be non-negative");
2043 assert(MI->getOperand(2).getImm() <= 1008 &&
2044 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
2045 TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(),
2046 MI->getOperand(2).getImm());
2047 return;
2048
2049 case AArch64::SEH_SaveAnyRegQPX:
2050 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
2051 "Non-consecutive registers not allowed for save_any_reg");
2052 assert(MI->getOperand(2).getImm() < 0 &&
2053 "SaveAnyRegQPX SEH opcode offset must be negative");
2054 assert(MI->getOperand(2).getImm() >= -1008 &&
2055 "SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
2056 TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(),
2057 -MI->getOperand(2).getImm());
2058 return;
2059 }
2060
2061 // Finally, do the automated lowerings for everything else.
2062 MCInst TmpInst;
2063 MCInstLowering.Lower(MI, TmpInst);
2064 EmitToStreamer(*OutStreamer, TmpInst);
2065}
2066
2067void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
2068 MCSymbol *LazyPointer) {
2069 // _ifunc:
2070 // adrp x16, lazy_pointer@GOTPAGE
2071 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
2072 // ldr x16, [x16]
2073 // br x16
2074
2075 {
2076 MCInst Adrp;
2077 Adrp.setOpcode(AArch64::ADRP);
2078 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
2079 MCOperand SymPage;
2080 MCInstLowering.lowerOperand(
2083 SymPage);
2084 Adrp.addOperand(SymPage);
2085 OutStreamer->emitInstruction(Adrp, *STI);
2086 }
2087
2088 {
2089 MCInst Ldr;
2090 Ldr.setOpcode(AArch64::LDRXui);
2091 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2092 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2093 MCOperand SymPageOff;
2094 MCInstLowering.lowerOperand(
2097 SymPageOff);
2098 Ldr.addOperand(SymPageOff);
2100 OutStreamer->emitInstruction(Ldr, *STI);
2101 }
2102
2103 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
2104 .addReg(AArch64::X16)
2105 .addReg(AArch64::X16)
2106 .addImm(0),
2107 *STI);
2108
2109 OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
2110 ? AArch64::BRAAZ
2111 : AArch64::BR)
2112 .addReg(AArch64::X16),
2113 *STI);
2114}
2115
2116void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
2117 const GlobalIFunc &GI,
2118 MCSymbol *LazyPointer) {
2119 // These stub helpers are only ever called once, so here we're optimizing for
2120 // minimum size by using the pre-indexed store variants, which saves a few
2121 // bytes of instructions to bump & restore sp.
2122
2123 // _ifunc.stub_helper:
2124 // stp fp, lr, [sp, #-16]!
2125 // mov fp, sp
2126 // stp x1, x0, [sp, #-16]!
2127 // stp x3, x2, [sp, #-16]!
2128 // stp x5, x4, [sp, #-16]!
2129 // stp x7, x6, [sp, #-16]!
2130 // stp d1, d0, [sp, #-16]!
2131 // stp d3, d2, [sp, #-16]!
2132 // stp d5, d4, [sp, #-16]!
2133 // stp d7, d6, [sp, #-16]!
2134 // bl _resolver
2135 // adrp x16, lazy_pointer@GOTPAGE
2136 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
2137 // str x0, [x16]
2138 // mov x16, x0
2139 // ldp d7, d6, [sp], #16
2140 // ldp d5, d4, [sp], #16
2141 // ldp d3, d2, [sp], #16
2142 // ldp d1, d0, [sp], #16
2143 // ldp x7, x6, [sp], #16
2144 // ldp x5, x4, [sp], #16
2145 // ldp x3, x2, [sp], #16
2146 // ldp x1, x0, [sp], #16
2147 // ldp fp, lr, [sp], #16
2148 // br x16
2149
2150 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
2151 .addReg(AArch64::SP)
2152 .addReg(AArch64::FP)
2153 .addReg(AArch64::LR)
2154 .addReg(AArch64::SP)
2155 .addImm(-2),
2156 *STI);
2157
2158 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
2159 .addReg(AArch64::FP)
2160 .addReg(AArch64::SP)
2161 .addImm(0)
2162 .addImm(0),
2163 *STI);
2164
2165 for (int I = 0; I != 4; ++I)
2166 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
2167 .addReg(AArch64::SP)
2168 .addReg(AArch64::X1 + 2 * I)
2169 .addReg(AArch64::X0 + 2 * I)
2170 .addReg(AArch64::SP)
2171 .addImm(-2),
2172 *STI);
2173
2174 for (int I = 0; I != 4; ++I)
2175 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
2176 .addReg(AArch64::SP)
2177 .addReg(AArch64::D1 + 2 * I)
2178 .addReg(AArch64::D0 + 2 * I)
2179 .addReg(AArch64::SP)
2180 .addImm(-2),
2181 *STI);
2182
2183 OutStreamer->emitInstruction(
2184 MCInstBuilder(AArch64::BL)
2186 *STI);
2187
2188 {
2189 MCInst Adrp;
2190 Adrp.setOpcode(AArch64::ADRP);
2191 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
2192 MCOperand SymPage;
2193 MCInstLowering.lowerOperand(
2194 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
2196 SymPage);
2197 Adrp.addOperand(SymPage);
2198 OutStreamer->emitInstruction(Adrp, *STI);
2199 }
2200
2201 {
2202 MCInst Ldr;
2203 Ldr.setOpcode(AArch64::LDRXui);
2204 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2205 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2206 MCOperand SymPageOff;
2207 MCInstLowering.lowerOperand(
2208 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
2210 SymPageOff);
2211 Ldr.addOperand(SymPageOff);
2213 OutStreamer->emitInstruction(Ldr, *STI);
2214 }
2215
2216 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
2217 .addReg(AArch64::X0)
2218 .addReg(AArch64::X16)
2219 .addImm(0),
2220 *STI);
2221
2222 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
2223 .addReg(AArch64::X16)
2224 .addReg(AArch64::X0)
2225 .addImm(0)
2226 .addImm(0),
2227 *STI);
2228
2229 for (int I = 3; I != -1; --I)
2230 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
2231 .addReg(AArch64::SP)
2232 .addReg(AArch64::D1 + 2 * I)
2233 .addReg(AArch64::D0 + 2 * I)
2234 .addReg(AArch64::SP)
2235 .addImm(2),
2236 *STI);
2237
2238 for (int I = 3; I != -1; --I)
2239 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
2240 .addReg(AArch64::SP)
2241 .addReg(AArch64::X1 + 2 * I)
2242 .addReg(AArch64::X0 + 2 * I)
2243 .addReg(AArch64::SP)
2244 .addImm(2),
2245 *STI);
2246
2247 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
2248 .addReg(AArch64::SP)
2249 .addReg(AArch64::FP)
2250 .addReg(AArch64::LR)
2251 .addReg(AArch64::SP)
2252 .addImm(2),
2253 *STI);
2254
2255 OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
2256 ? AArch64::BRAAZ
2257 : AArch64::BR)
2258 .addReg(AArch64::X16),
2259 *STI);
2260}
2261
2262const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV) {
2263 if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
2264 return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0),
2265 OutContext);
2266 }
2267
2268 return AsmPrinter::lowerConstant(CV);
2269}
2270
2271// Force static initialization.
2278}
LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter()
MachineBasicBlock & MBB
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
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
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)
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)
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:84
virtual void emitInstruction(const MachineInstr *)
Targets should implement this to emit instructions.
Definition: AsmPrinter.h:567
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:612
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:543
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:547
virtual void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI, MCSymbol *LazyPointer)
Definition: AsmPrinter.h:606
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
Definition: AsmPrinter.cpp:441
virtual bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const
Definition: AsmPrinter.h:911
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:602
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition: AsmPrinter.h:395
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:555
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.
This is an important base class in LLVM.
Definition: Constant.h:41
This class represents an Operation in the Expression.
const Constant * getResolver() const
Definition: GlobalIFunc.h:70
bool hasLocalLinkage() const
Definition: GlobalValue.h:527
static const MCBinaryExpr * createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:616
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:621
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:194
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35
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
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:39
Streaming machine code generation interface.
Definition: MCStreamer.h:212
virtual void emitCFIBKeyFrame()
Definition: MCStreamer.cpp:249
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:342
virtual void endCOFFSymbolDef()
Marks the end of the symbol definition.
MCContext & getContext() const
Definition: MCStreamer.h:297
virtual void AddComment(const Twine &T, bool EOL=true)
Add a textual comment.
Definition: MCStreamer.h:361
virtual void emitCFIMTETaggedFrame()
Definition: MCStreamer.cpp:256
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
Definition: MCStreamer.cpp:424
MCTargetStreamer * getTargetStreamer()
Definition: MCStreamer.h:306
void emitRawText(const Twine &String)
If this file is backed by a assembly streamer, this dumps the specified string in the output ....
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:192
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:397
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:40
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:680
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:574
const std::vector< MachineJumpTableEntry > & getJumpTables() const
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
static MachineOperand CreateMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
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
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.
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
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:76
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
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
@ SHF_ALLOC
Definition: ELF.h:1161
@ SHF_GROUP
Definition: ELF.h:1183
@ SHF_EXECINSTR
Definition: ELF.h:1164
@ SHT_PROGBITS
Definition: ELF.h:1067
@ GNU_PROPERTY_AARCH64_FEATURE_1_BTI
Definition: ELF.h:1756
@ GNU_PROPERTY_AARCH64_FEATURE_1_PAC
Definition: ELF.h:1757
@ GNU_PROPERTY_AARCH64_FEATURE_1_GCS
Definition: ELF.h:1758
Reg
All possible values of the reg field in the ModR/M byte.
constexpr double e
Definition: MathExtras.h:31
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
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:159
Target & getTheARM64_32Target()
@ MCAF_SubsectionsViaSymbols
.subsections_via_symbols (MachO)
Definition: MCDirectives.h:55
@ Add
Sum of integers.
static unsigned getWRegFromXReg(unsigned Reg)
Target & getTheARM64Target()
@ 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,...