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