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