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