LLVM 23.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"
27#include "llvm/ADT/DenseMap.h"
28#include "llvm/ADT/ScopeExit.h"
31#include "llvm/ADT/Statistic.h"
32#include "llvm/ADT/StringRef.h"
33#include "llvm/ADT/Twine.h"
47#include "llvm/IR/DataLayout.h"
49#include "llvm/IR/Mangler.h"
50#include "llvm/IR/Module.h"
51#include "llvm/MC/MCAsmInfo.h"
52#include "llvm/MC/MCContext.h"
53#include "llvm/MC/MCExpr.h"
54#include "llvm/MC/MCInst.h"
58#include "llvm/MC/MCStreamer.h"
59#include "llvm/MC/MCSymbol.h"
60#include "llvm/MC/MCValue.h"
70#include <cassert>
71#include <cstdint>
72#include <map>
73#include <memory>
74
75using namespace llvm;
76
77#define DEBUG_TYPE "AArch64AsmPrinter"
78
79// Doesn't count FPR128 ZCZ instructions which are handled
80// by TableGen pattern matching
81STATISTIC(NumZCZeroingInstrsFPR,
82 "Number of zero-cycle FPR zeroing instructions expanded from "
83 "canonical pseudo instructions");
84
87 "aarch64-ptrauth-auth-checks", cl::Hidden,
88 cl::values(clEnumValN(Unchecked, "none", "don't test for failure"),
89 clEnumValN(Poison, "poison", "poison on failure"),
90 clEnumValN(Trap, "trap", "trap on failure")),
91 cl::desc("Check pointer authentication auth/resign failures"),
93
94namespace {
95
96class AArch64AsmPrinter : public AsmPrinter {
97 AArch64MCInstLower MCInstLowering;
98 FaultMaps FM;
99 const AArch64Subtarget *STI;
100 bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false;
101#ifndef NDEBUG
102 unsigned InstsEmitted;
103#endif
104 bool EnableImportCallOptimization = false;
106 SectionToImportedFunctionCalls;
107 unsigned PAuthIFuncNextUniqueID = 1;
108
109public:
110 static char ID;
111
112 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
113 : AsmPrinter(TM, std::move(Streamer), ID),
114 MCInstLowering(OutContext, *this), FM(*this) {}
115
116 StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
117
118 /// Wrapper for MCInstLowering.lowerOperand() for the
119 /// tblgen'erated pseudo lowering.
120 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
121 return MCInstLowering.lowerOperand(MO, MCOp);
122 }
123
124 const MCExpr *lowerConstantPtrAuth(const ConstantPtrAuth &CPA) override;
125
126 const MCExpr *lowerBlockAddressConstant(const BlockAddress &BA) override;
127
128 void emitStartOfAsmFile(Module &M) override;
129 void emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
130 ArrayRef<unsigned> JumpTableIndices) override;
131 std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
133 getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
134 const MCSymbol *BranchLabel) const override;
135
136 void emitFunctionEntryLabel() override;
137
138 void emitXXStructor(const DataLayout &DL, const Constant *CV) override;
139
140 void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
141
142 void LowerHardenedBRJumpTable(const MachineInstr &MI);
143
144 void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI);
145
146 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
147 const MachineInstr &MI);
148 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
149 const MachineInstr &MI);
150 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
151 const MachineInstr &MI);
152 void LowerFAULTING_OP(const MachineInstr &MI);
153
154 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
155 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
156 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
157 void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
158
159 typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
160 HwasanMemaccessTuple;
161 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
162 void LowerKCFI_CHECK(const MachineInstr &MI);
163 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
164 void emitHwasanMemaccessSymbols(Module &M);
165
166 void emitSled(const MachineInstr &MI, SledKind Kind);
167
168 // Returns whether Reg may be used to store sensitive temporary values when
169 // expanding PtrAuth pseudos. Some OSes may take extra care to protect a
170 // small subset of GPRs on context switches - use these registers then.
171 //
172 // If there are no preferred registers, returns true for any Reg.
173 bool isPtrauthRegSafe(Register Reg) const {
174 if (STI->isX16X17Safer())
175 return Reg == AArch64::X16 || Reg == AArch64::X17;
176
177 return true;
178 }
179
180 // Emit the sequence for BRA/BLRA (authenticate + branch/call).
181 void emitPtrauthBranch(const MachineInstr *MI);
182
183 void emitPtrauthCheckAuthenticatedValue(Register TestedReg,
184 Register ScratchReg,
187 const MCSymbol *OnFailure = nullptr);
188
189 // Check authenticated LR before tail calling.
190 void emitPtrauthTailCallHardening(const MachineInstr *TC);
191
192 struct PtrAuthSchema {
193 PtrAuthSchema(AArch64PACKey::ID Key, uint64_t IntDisc,
194 const MachineOperand &AddrDiscOp);
195
197 uint64_t IntDisc;
198 Register AddrDisc;
199 bool AddrDiscIsKilled;
200 };
201
202 // Helper for emitting AUTRELLOADPAC: increment Pointer by Addend and then by
203 // a 32-bit signed value loaded from memory. The instructions emitted are
204 //
205 // ldrsw Scratch, [Pointer, #Addend]!
206 // add Pointer, Pointer, Scratch
207 //
208 // for small Addend value, with longer sequences required for wider Addend.
209 void emitPtrauthApplyIndirectAddend(Register Pointer, Register Scratch,
210 int64_t Addend);
211
212 // Emit the sequence for AUT or AUTPAC. Addend if AUTRELLOADPAC
213 void emitPtrauthAuthResign(Register Pointer, Register Scratch,
214 PtrAuthSchema AuthSchema,
215 std::optional<PtrAuthSchema> SignSchema,
216 std::optional<int64_t> Addend, Value *DS);
217
218 // Emit R_AARCH64_PATCHINST, the deactivation symbol relocation. Returns true
219 // if no instruction should be emitted because the deactivation symbol is
220 // defined in the current module so this function emitted a NOP instead.
221 bool emitDeactivationSymbolRelocation(Value *DS);
222
223 // Emit the sequence for PAC.
224 void emitPtrauthSign(const MachineInstr *MI);
225
226 // Emit the sequence to compute the discriminator.
227 //
228 // The Scratch register passed to this function must be safe, as returned by
229 // isPtrauthRegSafe(ScratchReg).
230 //
231 // The returned register is either ScratchReg, AddrDisc, or XZR. Furthermore,
232 // it is guaranteed to be safe (or XZR), with the only exception of
233 // passing-through an *unmodified* unsafe AddrDisc register.
234 //
235 // If the expanded pseudo is allowed to clobber AddrDisc register, setting
236 // MayClobberAddrDisc may save one MOV instruction, provided
237 // isPtrauthRegSafe(AddrDisc) is true:
238 //
239 // mov x17, x16
240 // movk x17, #1234, lsl #48
241 // ; x16 is not used anymore
242 //
243 // can be replaced by
244 //
245 // movk x16, #1234, lsl #48
246 Register emitPtrauthDiscriminator(uint64_t Disc, Register AddrDisc,
247 Register ScratchReg,
248 bool MayClobberAddrDisc = false);
249
250 // Emit the sequence for LOADauthptrstatic
251 void LowerLOADauthptrstatic(const MachineInstr &MI);
252
253 // Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or
254 // adrp-add followed by PAC sign)
255 void LowerMOVaddrPAC(const MachineInstr &MI);
256
257 // Emit the sequence for LOADgotAUTH (load signed pointer from signed ELF GOT
258 // and authenticate it with, if FPAC bit is not set, check+trap sequence after
259 // authenticating)
260 void LowerLOADgotAUTH(const MachineInstr &MI);
261
262 void emitAddImm(MCRegister Val, int64_t Addend, MCRegister Tmp);
263 void emitAddress(MCRegister Reg, const MCExpr *Expr, MCRegister Tmp,
264 bool DSOLocal, const MCSubtargetInfo &STI);
265
266 const MCExpr *emitPAuthRelocationAsIRelative(
267 const MCExpr *Target, uint64_t Disc, AArch64PACKey::ID KeyID,
268 bool HasAddressDiversity, bool IsDSOLocal, const MCExpr *DSExpr);
269
270 /// tblgen'erated driver function for lowering simple MI->MC
271 /// pseudo instructions.
272 bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
273
274 // Emit Build Attributes
275 void emitAttributes(unsigned Flags, uint64_t PAuthABIPlatform,
276 uint64_t PAuthABIVersion, AArch64TargetStreamer *TS);
277
278 // Emit expansion of Compare-and-branch pseudo instructions
279 void emitCBPseudoExpansion(const MachineInstr *MI);
280
281 void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
282 void EmitToStreamer(const MCInst &Inst) {
283 EmitToStreamer(*OutStreamer, Inst);
284 }
285
286 void emitInstruction(const MachineInstr *MI) override;
287
288 void emitFunctionHeaderComment() override;
289
290 void getAnalysisUsage(AnalysisUsage &AU) const override {
292 AU.setPreservesAll();
293 }
294
295 bool runOnMachineFunction(MachineFunction &MF) override {
296 if (auto *PSIW = getAnalysisIfAvailable<ProfileSummaryInfoWrapperPass>())
297 PSI = &PSIW->getPSI();
298 if (auto *SDPIW =
299 getAnalysisIfAvailable<StaticDataProfileInfoWrapperPass>())
300 SDPI = &SDPIW->getStaticDataProfileInfo();
301
302 AArch64FI = MF.getInfo<AArch64FunctionInfo>();
303 STI = &MF.getSubtarget<AArch64Subtarget>();
304
305 SetupMachineFunction(MF);
306
307 if (STI->isTargetCOFF()) {
308 bool Local = MF.getFunction().hasLocalLinkage();
311 int Type =
313
314 OutStreamer->beginCOFFSymbolDef(CurrentFnSym);
315 OutStreamer->emitCOFFSymbolStorageClass(Scl);
316 OutStreamer->emitCOFFSymbolType(Type);
317 OutStreamer->endCOFFSymbolDef();
318 }
319
320 // Emit the rest of the function body.
321 emitFunctionBody();
322
323 // Emit the XRay table for this function.
324 emitXRayTable();
325
326 // We didn't modify anything.
327 return false;
328 }
329
330 const MCExpr *lowerConstant(const Constant *CV,
331 const Constant *BaseCV = nullptr,
332 uint64_t Offset = 0) override;
333
334private:
335 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
336 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
337 bool printAsmRegInClass(const MachineOperand &MO,
338 const TargetRegisterClass *RC, unsigned AltName,
339 raw_ostream &O);
340
341 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
342 const char *ExtraCode, raw_ostream &O) override;
343 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
344 const char *ExtraCode, raw_ostream &O) override;
345
346 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
347
348 void emitFunctionBodyEnd() override;
349 void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
350
351 MCSymbol *GetCPISymbol(unsigned CPID) const override;
352 void emitEndOfAsmFile(Module &M) override;
353
354 AArch64FunctionInfo *AArch64FI = nullptr;
355
356 /// Emit the LOHs contained in AArch64FI.
357 void emitLOHs();
358
359 void emitMovXReg(Register Dest, Register Src);
360 void emitMOVZ(Register Dest, uint64_t Imm, unsigned Shift);
361 void emitMOVK(Register Dest, uint64_t Imm, unsigned Shift);
362
363 void emitAUT(AArch64PACKey::ID Key, Register Pointer, Register Disc);
364 void emitPAC(AArch64PACKey::ID Key, Register Pointer, Register Disc);
365 void emitBLRA(bool IsCall, AArch64PACKey::ID Key, Register Target,
366 Register Disc);
367
368 /// Emit instruction to set float register to zero.
369 void emitFMov0(const MachineInstr &MI);
370 void emitFMov0AsFMov(const MachineInstr &MI, Register DestReg);
371
372 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
373
374 MInstToMCSymbol LOHInstToLabel;
375
376 bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
377 return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
378 }
379
380 const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
381 assert(STI);
382 return STI;
383 }
384 void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
385 MCSymbol *LazyPointer) override;
386 void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
387 MCSymbol *LazyPointer) override;
388
389 /// Checks if this instruction is part of a sequence that is eligle for import
390 /// call optimization and, if so, records it to be emitted in the import call
391 /// section.
392 void recordIfImportCall(const MachineInstr *BranchInst);
393};
394
395} // end anonymous namespace
396
397void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
398 const Triple &TT = TM.getTargetTriple();
399
400 if (TT.isOSBinFormatCOFF()) {
401 emitCOFFFeatureSymbol(M);
402 emitCOFFReplaceableFunctionData(M);
403
404 if (M.getModuleFlag("import-call-optimization"))
405 EnableImportCallOptimization = true;
406 }
407
408 if (!TT.isOSBinFormatELF())
409 return;
410
411 // For emitting build attributes and .note.gnu.property section
412 auto *TS =
413 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
414 // Assemble feature flags that may require creation of build attributes and a
415 // note section.
416 unsigned BAFlags = 0;
417 unsigned GNUFlags = 0;
418 if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
419 M.getModuleFlag("branch-target-enforcement"))) {
420 if (!BTE->isZero()) {
421 BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_BTI_Flag;
423 }
424 }
425
426 if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
427 M.getModuleFlag("guarded-control-stack"))) {
428 if (!GCS->isZero()) {
429 BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_GCS_Flag;
431 }
432 }
433
434 if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
435 M.getModuleFlag("sign-return-address"))) {
436 if (!Sign->isZero()) {
437 BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_PAC_Flag;
439 }
440 }
441
442 uint64_t PAuthABIPlatform = -1;
443 if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
444 M.getModuleFlag("aarch64-elf-pauthabi-platform"))) {
445 PAuthABIPlatform = PAP->getZExtValue();
446 }
447
448 uint64_t PAuthABIVersion = -1;
449 if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
450 M.getModuleFlag("aarch64-elf-pauthabi-version"))) {
451 PAuthABIVersion = PAV->getZExtValue();
452 }
453
454 // Emit AArch64 Build Attributes
455 emitAttributes(BAFlags, PAuthABIPlatform, PAuthABIVersion, TS);
456 // Emit a .note.gnu.property section with the flags.
457 TS->emitNoteSection(GNUFlags, PAuthABIPlatform, PAuthABIVersion);
458}
459
460void AArch64AsmPrinter::emitFunctionHeaderComment() {
461 const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>();
462 std::optional<std::string> OutlinerString = FI->getOutliningStyle();
463 if (OutlinerString != std::nullopt)
464 OutStreamer->getCommentOS() << ' ' << OutlinerString;
465}
466
467void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
468{
469 const Function &F = MF->getFunction();
470 if (F.hasFnAttribute("patchable-function-entry")) {
471 unsigned Num;
472 if (F.getFnAttribute("patchable-function-entry")
473 .getValueAsString()
474 .getAsInteger(10, Num))
475 return;
476 emitNops(Num);
477 return;
478 }
479
480 emitSled(MI, SledKind::FUNCTION_ENTER);
481}
482
483void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
484 emitSled(MI, SledKind::FUNCTION_EXIT);
485}
486
487void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
488 emitSled(MI, SledKind::TAIL_CALL);
489}
490
491void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
492 static const int8_t NoopsInSledCount = 7;
493 // We want to emit the following pattern:
494 //
495 // .Lxray_sled_N:
496 // ALIGN
497 // B #32
498 // ; 7 NOP instructions (28 bytes)
499 // .tmpN
500 //
501 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
502 // over the full 32 bytes (8 instructions) with the following pattern:
503 //
504 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
505 // LDR W17, #12 ; W17 := function ID
506 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
507 // BLR X16 ; call the tracing trampoline
508 // ;DATA: 32 bits of function ID
509 // ;DATA: lower 32 bits of the address of the trampoline
510 // ;DATA: higher 32 bits of the address of the trampoline
511 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
512 //
513 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
514 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
515 OutStreamer->emitLabel(CurSled);
516 auto Target = OutContext.createTempSymbol();
517
518 // Emit "B #32" instruction, which jumps over the next 28 bytes.
519 // The operand has to be the number of 4-byte instructions to jump over,
520 // including the current instruction.
521 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
522
523 for (int8_t I = 0; I < NoopsInSledCount; I++)
524 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::NOP));
525
526 OutStreamer->emitLabel(Target);
527 recordSled(CurSled, MI, Kind, 2);
528}
529
530void AArch64AsmPrinter::emitAttributes(unsigned Flags,
531 uint64_t PAuthABIPlatform,
532 uint64_t PAuthABIVersion,
533 AArch64TargetStreamer *TS) {
534
535 PAuthABIPlatform = (uint64_t(-1) == PAuthABIPlatform) ? 0 : PAuthABIPlatform;
536 PAuthABIVersion = (uint64_t(-1) == PAuthABIVersion) ? 0 : PAuthABIVersion;
537
538 if (PAuthABIPlatform || PAuthABIVersion) {
542 AArch64BuildAttributes::SubsectionOptional::REQUIRED,
543 AArch64BuildAttributes::SubsectionType::ULEB128);
547 PAuthABIPlatform, "");
551 "");
552 }
553
554 unsigned BTIValue =
556 unsigned PACValue =
558 unsigned GCSValue =
560
561 if (BTIValue || PACValue || GCSValue) {
565 AArch64BuildAttributes::SubsectionOptional::OPTIONAL,
566 AArch64BuildAttributes::SubsectionType::ULEB128);
576 }
577}
578
579// Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
580// (built-in functions __xray_customevent/__xray_typedevent).
581//
582// .Lxray_event_sled_N:
583// b 1f
584// save x0 and x1 (and also x2 for TYPED_EVENT_CALL)
585// set up x0 and x1 (and also x2 for TYPED_EVENT_CALL)
586// bl __xray_CustomEvent or __xray_TypedEvent
587// restore x0 and x1 (and also x2 for TYPED_EVENT_CALL)
588// 1:
589//
590// There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL.
591//
592// Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT.
593// After patching, b .+N will become a nop.
594void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
595 bool Typed) {
596 auto &O = *OutStreamer;
597 MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
598 O.emitLabel(CurSled);
599 bool MachO = TM.getTargetTriple().isOSBinFormatMachO();
600 auto *Sym = MCSymbolRefExpr::create(
601 OutContext.getOrCreateSymbol(
602 Twine(MachO ? "_" : "") +
603 (Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")),
604 OutContext);
605 if (Typed) {
606 O.AddComment("Begin XRay typed event");
607 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9));
608 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
609 .addReg(AArch64::SP)
610 .addReg(AArch64::X0)
611 .addReg(AArch64::X1)
612 .addReg(AArch64::SP)
613 .addImm(-4));
614 EmitToStreamer(O, MCInstBuilder(AArch64::STRXui)
615 .addReg(AArch64::X2)
616 .addReg(AArch64::SP)
617 .addImm(2));
618 emitMovXReg(AArch64::X0, MI.getOperand(0).getReg());
619 emitMovXReg(AArch64::X1, MI.getOperand(1).getReg());
620 emitMovXReg(AArch64::X2, MI.getOperand(2).getReg());
621 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
622 EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui)
623 .addReg(AArch64::X2)
624 .addReg(AArch64::SP)
625 .addImm(2));
626 O.AddComment("End XRay typed event");
627 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
628 .addReg(AArch64::SP)
629 .addReg(AArch64::X0)
630 .addReg(AArch64::X1)
631 .addReg(AArch64::SP)
632 .addImm(4));
633
634 recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2);
635 } else {
636 O.AddComment("Begin XRay custom event");
637 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6));
638 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
639 .addReg(AArch64::SP)
640 .addReg(AArch64::X0)
641 .addReg(AArch64::X1)
642 .addReg(AArch64::SP)
643 .addImm(-2));
644 emitMovXReg(AArch64::X0, MI.getOperand(0).getReg());
645 emitMovXReg(AArch64::X1, MI.getOperand(1).getReg());
646 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
647 O.AddComment("End XRay custom event");
648 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
649 .addReg(AArch64::SP)
650 .addReg(AArch64::X0)
651 .addReg(AArch64::X1)
652 .addReg(AArch64::SP)
653 .addImm(2));
654
655 recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2);
656 }
657}
658
659void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
660 Register AddrReg = MI.getOperand(0).getReg();
661 assert(std::next(MI.getIterator())->isCall() &&
662 "KCFI_CHECK not followed by a call instruction");
663 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
664 "KCFI_CHECK call target doesn't match call operand");
665
666 // Default to using the intra-procedure-call temporary registers for
667 // comparing the hashes.
668 unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
669 if (AddrReg == AArch64::XZR) {
670 // Checking XZR makes no sense. Instead of emitting a load, zero
671 // ScratchRegs[0] and use it for the ESR AddrIndex below.
672 AddrReg = getXRegFromWReg(ScratchRegs[0]);
673 emitMovXReg(AddrReg, AArch64::XZR);
674 } else {
675 // If one of the scratch registers is used for the call target (e.g.
676 // with AArch64::TCRETURNriBTI), we can clobber another caller-saved
677 // temporary register instead (in this case, AArch64::W9) as the check
678 // is immediately followed by the call instruction.
679 for (auto &Reg : ScratchRegs) {
680 if (Reg == getWRegFromXReg(AddrReg)) {
681 Reg = AArch64::W9;
682 break;
683 }
684 }
685 assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
686 "Invalid scratch registers for KCFI_CHECK");
687
688 // Adjust the offset for patchable-function-prefix. This assumes that
689 // patchable-function-prefix is the same for all functions.
690 int64_t PrefixNops = 0;
691 (void)MI.getMF()
692 ->getFunction()
693 .getFnAttribute("patchable-function-prefix")
694 .getValueAsString()
695 .getAsInteger(10, PrefixNops);
696
697 // Load the target function type hash.
698 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
699 .addReg(ScratchRegs[0])
700 .addReg(AddrReg)
701 .addImm(-(PrefixNops * 4 + 4)));
702 }
703
704 // Load the expected type hash.
705 const int64_t Type = MI.getOperand(1).getImm();
706 emitMOVK(ScratchRegs[1], Type & 0xFFFF, 0);
707 emitMOVK(ScratchRegs[1], (Type >> 16) & 0xFFFF, 16);
708
709 // Compare the hashes and trap if there's a mismatch.
710 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs)
711 .addReg(AArch64::WZR)
712 .addReg(ScratchRegs[0])
713 .addReg(ScratchRegs[1])
714 .addImm(0));
715
716 MCSymbol *Pass = OutContext.createTempSymbol();
717 EmitToStreamer(*OutStreamer,
718 MCInstBuilder(AArch64::Bcc)
719 .addImm(AArch64CC::EQ)
720 .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
721
722 // The base ESR is 0x8000 and the register information is encoded in bits
723 // 0-9 as follows:
724 // - 0-4: n, where the register Xn contains the target address
725 // - 5-9: m, where the register Wm contains the expected type hash
726 // Where n, m are in [0, 30].
727 unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
728 unsigned AddrIndex;
729 switch (AddrReg) {
730 default:
731 AddrIndex = AddrReg - AArch64::X0;
732 break;
733 case AArch64::FP:
734 AddrIndex = 29;
735 break;
736 case AArch64::LR:
737 AddrIndex = 30;
738 break;
739 }
740
741 assert(AddrIndex < 31 && TypeIndex < 31);
742
743 unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
744 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR));
745 OutStreamer->emitLabel(Pass);
746}
747
748void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
749 Register Reg = MI.getOperand(0).getReg();
750
751 // The HWASan pass won't emit a CHECK_MEMACCESS intrinsic with a pointer
752 // statically known to be zero. However, conceivably, the HWASan pass may
753 // encounter a "cannot currently statically prove to be null" pointer (and is
754 // therefore unable to omit the intrinsic) that later optimization passes
755 // convert into a statically known-null pointer.
756 if (Reg == AArch64::XZR)
757 return;
758
759 bool IsShort =
760 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
761 (MI.getOpcode() ==
762 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
763 uint32_t AccessInfo = MI.getOperand(1).getImm();
764 bool IsFixedShadow =
765 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
766 (MI.getOpcode() ==
767 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
768 uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0;
769
770 MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
771 Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
772 if (!Sym) {
773 // FIXME: Make this work on non-ELF.
774 if (!TM.getTargetTriple().isOSBinFormatELF())
775 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
776
777 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
778 utostr(AccessInfo);
779 if (IsFixedShadow)
780 SymName += "_fixed_" + utostr(FixedShadowOffset);
781 if (IsShort)
782 SymName += "_short_v2";
783 Sym = OutContext.getOrCreateSymbol(SymName);
784 }
785
786 EmitToStreamer(*OutStreamer,
787 MCInstBuilder(AArch64::BL)
788 .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
789}
790
791void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
792 if (HwasanMemaccessSymbols.empty())
793 return;
794
795 const Triple &TT = TM.getTargetTriple();
796 assert(TT.isOSBinFormatELF());
797 // AArch64Subtarget is huge, so heap allocate it so we don't run out of stack
798 // space.
799 auto STI = std::make_unique<AArch64Subtarget>(
800 TT, TM.getTargetCPU(), TM.getTargetCPU(), TM.getTargetFeatureString(), TM,
801 true);
802 this->STI = STI.get();
803
804 MCSymbol *HwasanTagMismatchV1Sym =
805 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
806 MCSymbol *HwasanTagMismatchV2Sym =
807 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
808
809 const MCSymbolRefExpr *HwasanTagMismatchV1Ref =
810 MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext);
811 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
812 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
813
814 for (auto &P : HwasanMemaccessSymbols) {
815 unsigned Reg = std::get<0>(P.first);
816 bool IsShort = std::get<1>(P.first);
817 uint32_t AccessInfo = std::get<2>(P.first);
818 bool IsFixedShadow = std::get<3>(P.first);
819 uint64_t FixedShadowOffset = std::get<4>(P.first);
820 const MCSymbolRefExpr *HwasanTagMismatchRef =
821 IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
822 MCSymbol *Sym = P.second;
823
824 bool HasMatchAllTag =
825 (AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1;
826 uint8_t MatchAllTag =
827 (AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff;
828 unsigned Size =
829 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
830 bool CompileKernel =
831 (AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1;
832
833 OutStreamer->switchSection(OutContext.getELFSection(
834 ".text.hot", ELF::SHT_PROGBITS,
836 /*IsComdat=*/true));
837
838 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
839 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
840 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
841 OutStreamer->emitLabel(Sym);
842
843 EmitToStreamer(MCInstBuilder(AArch64::SBFMXri)
844 .addReg(AArch64::X16)
845 .addReg(Reg)
846 .addImm(4)
847 .addImm(55));
848
849 if (IsFixedShadow) {
850 // Aarch64 makes it difficult to embed large constants in the code.
851 // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit
852 // left-shift option in the MOV instruction. Combined with the 16-bit
853 // immediate, this is enough to represent any offset up to 2**48.
854 emitMOVZ(AArch64::X17, FixedShadowOffset >> 32, 32);
855 EmitToStreamer(MCInstBuilder(AArch64::LDRBBroX)
856 .addReg(AArch64::W16)
857 .addReg(AArch64::X17)
858 .addReg(AArch64::X16)
859 .addImm(0)
860 .addImm(0));
861 } else {
862 EmitToStreamer(MCInstBuilder(AArch64::LDRBBroX)
863 .addReg(AArch64::W16)
864 .addReg(IsShort ? AArch64::X20 : AArch64::X9)
865 .addReg(AArch64::X16)
866 .addImm(0)
867 .addImm(0));
868 }
869
870 EmitToStreamer(MCInstBuilder(AArch64::SUBSXrs)
871 .addReg(AArch64::XZR)
872 .addReg(AArch64::X16)
873 .addReg(Reg)
875 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
876 EmitToStreamer(MCInstBuilder(AArch64::Bcc)
877 .addImm(AArch64CC::NE)
879 HandleMismatchOrPartialSym, OutContext)));
880 MCSymbol *ReturnSym = OutContext.createTempSymbol();
881 OutStreamer->emitLabel(ReturnSym);
882 EmitToStreamer(MCInstBuilder(AArch64::RET).addReg(AArch64::LR));
883 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
884
885 if (HasMatchAllTag) {
886 EmitToStreamer(MCInstBuilder(AArch64::UBFMXri)
887 .addReg(AArch64::X17)
888 .addReg(Reg)
889 .addImm(56)
890 .addImm(63));
891 EmitToStreamer(MCInstBuilder(AArch64::SUBSXri)
892 .addReg(AArch64::XZR)
893 .addReg(AArch64::X17)
894 .addImm(MatchAllTag)
895 .addImm(0));
896 EmitToStreamer(
897 MCInstBuilder(AArch64::Bcc)
898 .addImm(AArch64CC::EQ)
899 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)));
900 }
901
902 if (IsShort) {
903 EmitToStreamer(MCInstBuilder(AArch64::SUBSWri)
904 .addReg(AArch64::WZR)
905 .addReg(AArch64::W16)
906 .addImm(15)
907 .addImm(0));
908 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
909 EmitToStreamer(
910 MCInstBuilder(AArch64::Bcc)
911 .addImm(AArch64CC::HI)
912 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)));
913
914 EmitToStreamer(MCInstBuilder(AArch64::ANDXri)
915 .addReg(AArch64::X17)
916 .addReg(Reg)
917 .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)));
918 if (Size != 1)
919 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
920 .addReg(AArch64::X17)
921 .addReg(AArch64::X17)
922 .addImm(Size - 1)
923 .addImm(0));
924 EmitToStreamer(MCInstBuilder(AArch64::SUBSWrs)
925 .addReg(AArch64::WZR)
926 .addReg(AArch64::W16)
927 .addReg(AArch64::W17)
928 .addImm(0));
929 EmitToStreamer(
930 MCInstBuilder(AArch64::Bcc)
931 .addImm(AArch64CC::LS)
932 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)));
933
934 EmitToStreamer(MCInstBuilder(AArch64::ORRXri)
935 .addReg(AArch64::X16)
936 .addReg(Reg)
937 .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)));
938 EmitToStreamer(MCInstBuilder(AArch64::LDRBBui)
939 .addReg(AArch64::W16)
940 .addReg(AArch64::X16)
941 .addImm(0));
942 EmitToStreamer(
943 MCInstBuilder(AArch64::SUBSXrs)
944 .addReg(AArch64::XZR)
945 .addReg(AArch64::X16)
946 .addReg(Reg)
948 EmitToStreamer(
949 MCInstBuilder(AArch64::Bcc)
950 .addImm(AArch64CC::EQ)
951 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)));
952
953 OutStreamer->emitLabel(HandleMismatchSym);
954 }
955
956 EmitToStreamer(MCInstBuilder(AArch64::STPXpre)
957 .addReg(AArch64::SP)
958 .addReg(AArch64::X0)
959 .addReg(AArch64::X1)
960 .addReg(AArch64::SP)
961 .addImm(-32));
962 EmitToStreamer(MCInstBuilder(AArch64::STPXi)
963 .addReg(AArch64::FP)
964 .addReg(AArch64::LR)
965 .addReg(AArch64::SP)
966 .addImm(29));
967
968 if (Reg != AArch64::X0)
969 emitMovXReg(AArch64::X0, Reg);
970 emitMOVZ(AArch64::X1, AccessInfo & HWASanAccessInfo::RuntimeMask, 0);
971
972 if (CompileKernel) {
973 // The Linux kernel's dynamic loader doesn't support GOT relative
974 // relocations, but it doesn't support late binding either, so just call
975 // the function directly.
976 EmitToStreamer(MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef));
977 } else {
978 // Intentionally load the GOT entry and branch to it, rather than possibly
979 // late binding the function, which may clobber the registers before we
980 // have a chance to save them.
981 EmitToStreamer(MCInstBuilder(AArch64::ADRP)
982 .addReg(AArch64::X16)
983 .addExpr(MCSpecifierExpr::create(HwasanTagMismatchRef,
985 OutContext)));
986 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
987 .addReg(AArch64::X16)
988 .addReg(AArch64::X16)
989 .addExpr(MCSpecifierExpr::create(HwasanTagMismatchRef,
991 OutContext)));
992 EmitToStreamer(MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
993 }
994 }
995 this->STI = nullptr;
996}
997
998static void emitAuthenticatedPointer(MCStreamer &OutStreamer,
999 MCSymbol *StubLabel,
1000 const MCExpr *StubAuthPtrRef) {
1001 // sym$auth_ptr$key$disc:
1002 OutStreamer.emitLabel(StubLabel);
1003 OutStreamer.emitValue(StubAuthPtrRef, /*size=*/8);
1004}
1005
1006void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
1007 emitHwasanMemaccessSymbols(M);
1008
1009 const Triple &TT = TM.getTargetTriple();
1010 if (TT.isOSBinFormatMachO()) {
1011 // Output authenticated pointers as indirect symbols, if we have any.
1012 MachineModuleInfoMachO &MMIMacho =
1013 MMI->getObjFileInfo<MachineModuleInfoMachO>();
1014
1015 auto Stubs = MMIMacho.getAuthGVStubList();
1016
1017 if (!Stubs.empty()) {
1018 // Switch to the "__auth_ptr" section.
1019 OutStreamer->switchSection(
1020 OutContext.getMachOSection("__DATA", "__auth_ptr", MachO::S_REGULAR,
1022 emitAlignment(Align(8));
1023
1024 for (const auto &Stub : Stubs)
1025 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
1026
1027 OutStreamer->addBlankLine();
1028 }
1029
1030 // Funny Darwin hack: This flag tells the linker that no global symbols
1031 // contain code that falls through to other global symbols (e.g. the obvious
1032 // implementation of multiple entry points). If this doesn't occur, the
1033 // linker can safely perform dead code stripping. Since LLVM never
1034 // generates code that does this, it is always safe to set.
1035 OutStreamer->emitSubsectionsViaSymbols();
1036 }
1037
1038 if (TT.isOSBinFormatELF()) {
1039 // Output authenticated pointers as indirect symbols, if we have any.
1040 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
1041
1042 auto Stubs = MMIELF.getAuthGVStubList();
1043
1044 if (!Stubs.empty()) {
1045 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1046 OutStreamer->switchSection(TLOF.getDataSection());
1047 emitAlignment(Align(8));
1048
1049 for (const auto &Stub : Stubs)
1050 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
1051
1052 OutStreamer->addBlankLine();
1053 }
1054
1055 // With signed ELF GOT enabled, the linker looks at the symbol type to
1056 // choose between keys IA (for STT_FUNC) and DA (for other types). Symbols
1057 // for functions not defined in the module have STT_NOTYPE type by default.
1058 // This makes linker to emit signing schema with DA key (instead of IA) for
1059 // corresponding R_AARCH64_AUTH_GLOB_DAT dynamic reloc. To avoid that, force
1060 // all function symbols used in the module to have STT_FUNC type. See
1061 // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
1062 const auto *PtrAuthELFGOTFlag = mdconst::extract_or_null<ConstantInt>(
1063 M.getModuleFlag("ptrauth-elf-got"));
1064 if (PtrAuthELFGOTFlag && PtrAuthELFGOTFlag->getZExtValue() == 1)
1065 for (const GlobalValue &GV : M.global_values())
1066 if (!GV.use_empty() && isa<Function>(GV) &&
1067 !GV.getName().starts_with("llvm."))
1068 OutStreamer->emitSymbolAttribute(getSymbol(&GV),
1070 }
1071
1072 // Emit stack and fault map information.
1074
1075 // If import call optimization is enabled, emit the appropriate section.
1076 // We do this whether or not we recorded any import calls.
1077 if (EnableImportCallOptimization && TT.isOSBinFormatCOFF()) {
1078 OutStreamer->switchSection(getObjFileLowering().getImportCallSection());
1079
1080 // Section always starts with some magic.
1081 constexpr char ImpCallMagic[12] = "Imp_Call_V1";
1082 OutStreamer->emitBytes(StringRef{ImpCallMagic, sizeof(ImpCallMagic)});
1083
1084 // Layout of this section is:
1085 // Per section that contains calls to imported functions:
1086 // uint32_t SectionSize: Size in bytes for information in this section.
1087 // uint32_t Section Number
1088 // Per call to imported function in section:
1089 // uint32_t Kind: the kind of imported function.
1090 // uint32_t BranchOffset: the offset of the branch instruction in its
1091 // parent section.
1092 // uint32_t TargetSymbolId: the symbol id of the called function.
1093 for (auto &[Section, CallsToImportedFuncs] :
1094 SectionToImportedFunctionCalls) {
1095 unsigned SectionSize =
1096 sizeof(uint32_t) * (2 + 3 * CallsToImportedFuncs.size());
1097 OutStreamer->emitInt32(SectionSize);
1098 OutStreamer->emitCOFFSecNumber(Section->getBeginSymbol());
1099 for (auto &[CallsiteSymbol, CalledSymbol] : CallsToImportedFuncs) {
1100 // Kind is always IMAGE_REL_ARM64_DYNAMIC_IMPORT_CALL (0x13).
1101 OutStreamer->emitInt32(0x13);
1102 OutStreamer->emitCOFFSecOffset(CallsiteSymbol);
1103 OutStreamer->emitCOFFSymbolIndex(CalledSymbol);
1104 }
1105 }
1106 }
1107}
1108
1109void AArch64AsmPrinter::emitLOHs() {
1111
1112 for (const auto &D : AArch64FI->getLOHContainer()) {
1113 for (const MachineInstr *MI : D.getArgs()) {
1114 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
1115 assert(LabelIt != LOHInstToLabel.end() &&
1116 "Label hasn't been inserted for LOH related instruction");
1117 MCArgs.push_back(LabelIt->second);
1118 }
1119 OutStreamer->emitLOHDirective(D.getKind(), MCArgs);
1120 MCArgs.clear();
1121 }
1122}
1123
1124void AArch64AsmPrinter::emitFunctionBodyEnd() {
1125 if (!AArch64FI->getLOHRelated().empty())
1126 emitLOHs();
1127}
1128
1129/// GetCPISymbol - Return the symbol for the specified constant pool entry.
1130MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
1131 // Darwin uses a linker-private symbol name for constant-pools (to
1132 // avoid addends on the relocation?), ELF has no such concept and
1133 // uses a normal private symbol.
1134 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
1135 return OutContext.getOrCreateSymbol(
1136 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
1137 Twine(getFunctionNumber()) + "_" + Twine(CPID));
1138
1139 return AsmPrinter::GetCPISymbol(CPID);
1140}
1141
1142void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
1143 raw_ostream &O) {
1144 const MachineOperand &MO = MI->getOperand(OpNum);
1145 switch (MO.getType()) {
1146 default:
1147 llvm_unreachable("<unknown operand type>");
1149 Register Reg = MO.getReg();
1151 assert(!MO.getSubReg() && "Subregs should be eliminated!");
1153 break;
1154 }
1156 O << MO.getImm();
1157 break;
1158 }
1160 PrintSymbolOperand(MO, O);
1161 break;
1162 }
1164 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
1165 Sym->print(O, MAI);
1166 break;
1167 }
1168 }
1169}
1170
1171bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
1172 raw_ostream &O) {
1173 Register Reg = MO.getReg();
1174 switch (Mode) {
1175 default:
1176 return true; // Unknown mode.
1177 case 'w':
1179 break;
1180 case 'x':
1182 break;
1183 case 't':
1185 break;
1186 }
1187
1189 return false;
1190}
1191
1192// Prints the register in MO using class RC using the offset in the
1193// new register class. This should not be used for cross class
1194// printing.
1195bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
1196 const TargetRegisterClass *RC,
1197 unsigned AltName, raw_ostream &O) {
1198 assert(MO.isReg() && "Should only get here with a register!");
1199 const TargetRegisterInfo *RI = STI->getRegisterInfo();
1200 Register Reg = MO.getReg();
1201 MCRegister RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
1202 if (!RI->regsOverlap(RegToPrint, Reg))
1203 return true;
1204 O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName);
1205 return false;
1206}
1207
1208bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
1209 const char *ExtraCode, raw_ostream &O) {
1210 const MachineOperand &MO = MI->getOperand(OpNum);
1211
1212 // First try the generic code, which knows about modifiers like 'c' and 'n'.
1213 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
1214 return false;
1215
1216 // Does this asm operand have a single letter operand modifier?
1217 if (ExtraCode && ExtraCode[0]) {
1218 if (ExtraCode[1] != 0)
1219 return true; // Unknown modifier.
1220
1221 switch (ExtraCode[0]) {
1222 default:
1223 return true; // Unknown modifier.
1224 case 'w': // Print W register
1225 case 'x': // Print X register
1226 if (MO.isReg())
1227 return printAsmMRegister(MO, ExtraCode[0], O);
1228 if (MO.isImm() && MO.getImm() == 0) {
1229 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
1231 return false;
1232 }
1233 printOperand(MI, OpNum, O);
1234 return false;
1235 case 'b': // Print B register.
1236 case 'h': // Print H register.
1237 case 's': // Print S register.
1238 case 'd': // Print D register.
1239 case 'q': // Print Q register.
1240 case 'z': // Print Z register.
1241 if (MO.isReg()) {
1242 const TargetRegisterClass *RC;
1243 switch (ExtraCode[0]) {
1244 case 'b':
1245 RC = &AArch64::FPR8RegClass;
1246 break;
1247 case 'h':
1248 RC = &AArch64::FPR16RegClass;
1249 break;
1250 case 's':
1251 RC = &AArch64::FPR32RegClass;
1252 break;
1253 case 'd':
1254 RC = &AArch64::FPR64RegClass;
1255 break;
1256 case 'q':
1257 RC = &AArch64::FPR128RegClass;
1258 break;
1259 case 'z':
1260 RC = &AArch64::ZPRRegClass;
1261 break;
1262 default:
1263 return true;
1264 }
1265 return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
1266 }
1267 printOperand(MI, OpNum, O);
1268 return false;
1269 }
1270 }
1271
1272 // According to ARM, we should emit x and v registers unless we have a
1273 // modifier.
1274 if (MO.isReg()) {
1275 Register Reg = MO.getReg();
1276
1277 // If this is a w or x register, print an x register.
1278 if (AArch64::GPR32allRegClass.contains(Reg) ||
1279 AArch64::GPR64allRegClass.contains(Reg))
1280 return printAsmMRegister(MO, 'x', O);
1281
1282 // If this is an x register tuple, print an x register.
1283 if (AArch64::GPR64x8ClassRegClass.contains(Reg))
1284 return printAsmMRegister(MO, 't', O);
1285
1286 unsigned AltName = AArch64::NoRegAltName;
1287 const TargetRegisterClass *RegClass;
1288 if (AArch64::ZPRRegClass.contains(Reg)) {
1289 RegClass = &AArch64::ZPRRegClass;
1290 } else if (AArch64::PPRRegClass.contains(Reg)) {
1291 RegClass = &AArch64::PPRRegClass;
1292 } else if (AArch64::PNRRegClass.contains(Reg)) {
1293 RegClass = &AArch64::PNRRegClass;
1294 } else {
1295 RegClass = &AArch64::FPR128RegClass;
1296 AltName = AArch64::vreg;
1297 }
1298
1299 // If this is a b, h, s, d, or q register, print it as a v register.
1300 return printAsmRegInClass(MO, RegClass, AltName, O);
1301 }
1302
1303 printOperand(MI, OpNum, O);
1304 return false;
1305}
1306
1307bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1308 unsigned OpNum,
1309 const char *ExtraCode,
1310 raw_ostream &O) {
1311 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
1312 return true; // Unknown modifier.
1313
1314 const MachineOperand &MO = MI->getOperand(OpNum);
1315 assert(MO.isReg() && "unexpected inline asm memory operand");
1316 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
1317 return false;
1318}
1319
1320void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
1321 raw_ostream &OS) {
1322 unsigned NOps = MI->getNumOperands();
1323 assert(NOps == 4);
1324 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
1325 // cast away const; DIetc do not take const operands for some reason.
1326 OS << MI->getDebugVariable()->getName();
1327 OS << " <- ";
1328 // Frame address. Currently handles register +- offset only.
1329 assert(MI->isIndirectDebugValue());
1330 OS << '[';
1331 for (unsigned I = 0, E = llvm::size(MI->debug_operands()); I < E; ++I) {
1332 if (I != 0)
1333 OS << ", ";
1334 printOperand(MI, I, OS);
1335 }
1336 OS << ']';
1337 OS << "+";
1338 printOperand(MI, NOps - 2, OS);
1339}
1340
1341void AArch64AsmPrinter::emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
1342 ArrayRef<unsigned> JumpTableIndices) {
1343 // Fast return if there is nothing to emit to avoid creating empty sections.
1344 if (JumpTableIndices.empty())
1345 return;
1346 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
1347 const auto &F = MF->getFunction();
1349
1350 MCSection *ReadOnlySec = nullptr;
1351 if (TM.Options.EnableStaticDataPartitioning) {
1352 ReadOnlySec =
1353 TLOF.getSectionForJumpTable(F, TM, &JT[JumpTableIndices.front()]);
1354 } else {
1355 ReadOnlySec = TLOF.getSectionForJumpTable(F, TM);
1356 }
1357 OutStreamer->switchSection(ReadOnlySec);
1358
1359 auto AFI = MF->getInfo<AArch64FunctionInfo>();
1360 for (unsigned JTI : JumpTableIndices) {
1361 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
1362
1363 // If this jump table was deleted, ignore it.
1364 if (JTBBs.empty()) continue;
1365
1366 unsigned Size = AFI->getJumpTableEntrySize(JTI);
1367 emitAlignment(Align(Size));
1368 OutStreamer->emitLabel(GetJTISymbol(JTI));
1369
1370 const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1371 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
1372
1373 for (auto *JTBB : JTBBs) {
1374 const MCExpr *Value =
1375 MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext);
1376
1377 // Each entry is:
1378 // .byte/.hword (LBB - Lbase)>>2
1379 // or plain:
1380 // .word LBB - Lbase
1381 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
1382 if (Size != 4)
1384 Value, MCConstantExpr::create(2, OutContext), OutContext);
1385
1386 OutStreamer->emitValue(Value, Size);
1387 }
1388 }
1389}
1390
1391std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
1393AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI,
1394 const MachineInstr *BranchInstr,
1395 const MCSymbol *BranchLabel) const {
1396 const auto AFI = MF->getInfo<AArch64FunctionInfo>();
1397 const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1399 switch (AFI->getJumpTableEntrySize(JTI)) {
1400 case 1:
1401 EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
1402 break;
1403 case 2:
1404 EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
1405 break;
1406 case 4:
1407 EntrySize = codeview::JumpTableEntrySize::Int32;
1408 break;
1409 default:
1410 llvm_unreachable("Unexpected jump table entry size");
1411 }
1412 return std::make_tuple(Base, 0, BranchLabel, EntrySize);
1413}
1414
1415void AArch64AsmPrinter::emitFunctionEntryLabel() {
1416 const Triple &TT = TM.getTargetTriple();
1417 if (TT.isOSBinFormatELF() &&
1418 (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
1419 MF->getFunction().getCallingConv() ==
1420 CallingConv::AArch64_SVE_VectorCall ||
1421 MF->getInfo<AArch64FunctionInfo>()->isSVECC())) {
1422 auto *TS =
1423 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1424 TS->emitDirectiveVariantPCS(CurrentFnSym);
1425 }
1426
1428
1429 if (TT.isWindowsArm64EC() && !MF->getFunction().hasLocalLinkage()) {
1430 // For ARM64EC targets, a function definition's name is mangled differently
1431 // from the normal symbol, emit required aliases here.
1432 auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) {
1433 OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep);
1434 OutStreamer->emitAssignment(
1435 Src, MCSymbolRefExpr::create(Dst, MMI->getContext()));
1436 };
1437
1438 auto getSymbolFromMetadata = [&](StringRef Name) {
1439 MCSymbol *Sym = nullptr;
1440 if (MDNode *Node = MF->getFunction().getMetadata(Name)) {
1441 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1442 Sym = MMI->getContext().getOrCreateSymbol(NameStr);
1443 }
1444 return Sym;
1445 };
1446
1447 SmallVector<MDNode *> UnmangledNames;
1448 MF->getFunction().getMetadata("arm64ec_unmangled_name", UnmangledNames);
1449 for (MDNode *Node : UnmangledNames) {
1450 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
1451 MCSymbol *UnmangledSym = MMI->getContext().getOrCreateSymbol(NameStr);
1452 if (std::optional<std::string> MangledName =
1453 getArm64ECMangledFunctionName(UnmangledSym->getName())) {
1454 MCSymbol *ECMangledSym =
1455 MMI->getContext().getOrCreateSymbol(*MangledName);
1456 emitFunctionAlias(UnmangledSym, ECMangledSym);
1457 }
1458 }
1459 if (MCSymbol *ECMangledSym =
1460 getSymbolFromMetadata("arm64ec_ecmangled_name"))
1461 emitFunctionAlias(ECMangledSym, CurrentFnSym);
1462 }
1463}
1464
1465void AArch64AsmPrinter::emitXXStructor(const DataLayout &DL,
1466 const Constant *CV) {
1467 if (const auto *CPA = dyn_cast<ConstantPtrAuth>(CV))
1468 if (CPA->hasAddressDiscriminator() &&
1469 !CPA->hasSpecialAddressDiscriminator(
1472 "unexpected address discrimination value for ctors/dtors entry, only "
1473 "'ptr inttoptr (i64 1 to ptr)' is allowed");
1474 // If we have signed pointers in xxstructors list, they'll be lowered to @AUTH
1475 // MCExpr's via AArch64AsmPrinter::lowerConstantPtrAuth. It does not look at
1476 // actual address discrimination value and only checks
1477 // hasAddressDiscriminator(), so it's OK to leave special address
1478 // discrimination value here.
1480}
1481
1482void AArch64AsmPrinter::emitGlobalAlias(const Module &M,
1483 const GlobalAlias &GA) {
1484 if (auto F = dyn_cast_or_null<Function>(GA.getAliasee())) {
1485 // Global aliases must point to a definition, but unmangled patchable
1486 // symbols are special and need to point to an undefined symbol with "EXP+"
1487 // prefix. Such undefined symbol is resolved by the linker by creating
1488 // x86 thunk that jumps back to the actual EC target.
1489 if (MDNode *Node = F->getMetadata("arm64ec_exp_name")) {
1490 StringRef ExpStr = cast<MDString>(Node->getOperand(0))->getString();
1491 MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr);
1492 MCSymbol *Sym = MMI->getContext().getOrCreateSymbol(GA.getName());
1493
1494 OutStreamer->beginCOFFSymbolDef(ExpSym);
1495 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1496 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1498 OutStreamer->endCOFFSymbolDef();
1499
1500 OutStreamer->beginCOFFSymbolDef(Sym);
1501 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1502 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1504 OutStreamer->endCOFFSymbolDef();
1505 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
1506 OutStreamer->emitAssignment(
1507 Sym, MCSymbolRefExpr::create(ExpSym, MMI->getContext()));
1508 return;
1509 }
1510 }
1512}
1513
1514/// Small jump tables contain an unsigned byte or half, representing the offset
1515/// from the lowest-addressed possible destination to the desired basic
1516/// block. Since all instructions are 4-byte aligned, this is further compressed
1517/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
1518/// materialize the correct destination we need:
1519///
1520/// adr xDest, .LBB0_0
1521/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
1522/// add xDest, xDest, xScratch (with "lsl #2" for smaller entries)
1523void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer,
1524 const llvm::MachineInstr &MI) {
1525 Register DestReg = MI.getOperand(0).getReg();
1526 Register ScratchReg = MI.getOperand(1).getReg();
1527 Register ScratchRegW =
1528 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
1529 Register TableReg = MI.getOperand(2).getReg();
1530 Register EntryReg = MI.getOperand(3).getReg();
1531 int JTIdx = MI.getOperand(4).getIndex();
1532 int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
1533
1534 // This has to be first because the compression pass based its reachability
1535 // calculations on the start of the JumpTableDest instruction.
1536 auto Label =
1537 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
1538
1539 // If we don't already have a symbol to use as the base, use the ADR
1540 // instruction itself.
1541 if (!Label) {
1543 AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label);
1544 OutStreamer.emitLabel(Label);
1545 }
1546
1547 auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext());
1548 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
1549 .addReg(DestReg)
1550 .addExpr(LabelExpr));
1551
1552 // Load the number of instruction-steps to offset from the label.
1553 unsigned LdrOpcode;
1554 switch (Size) {
1555 case 1: LdrOpcode = AArch64::LDRBBroX; break;
1556 case 2: LdrOpcode = AArch64::LDRHHroX; break;
1557 case 4: LdrOpcode = AArch64::LDRSWroX; break;
1558 default:
1559 llvm_unreachable("Unknown jump table size");
1560 }
1561
1562 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
1563 .addReg(Size == 4 ? ScratchReg : ScratchRegW)
1564 .addReg(TableReg)
1565 .addReg(EntryReg)
1566 .addImm(0)
1567 .addImm(Size == 1 ? 0 : 1));
1568
1569 // Add to the already materialized base label address, multiplying by 4 if
1570 // compressed.
1571 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1572 .addReg(DestReg)
1573 .addReg(DestReg)
1574 .addReg(ScratchReg)
1575 .addImm(Size == 4 ? 0 : 2));
1576}
1577
1578void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) {
1579 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
1580 assert(MJTI && "Can't lower jump-table dispatch without JTI");
1581
1582 const std::vector<MachineJumpTableEntry> &JTs = MJTI->getJumpTables();
1583 assert(!JTs.empty() && "Invalid JT index for jump-table dispatch");
1584
1585 // Emit:
1586 // mov x17, #<size of table> ; depending on table size, with MOVKs
1587 // cmp x16, x17 ; or #imm if table size fits in 12-bit
1588 // csel x16, x16, xzr, ls ; check for index overflow
1589 //
1590 // adrp x17, Ltable@PAGE ; materialize table address
1591 // add x17, Ltable@PAGEOFF
1592 // ldrsw x16, [x17, x16, lsl #2] ; load table entry
1593 //
1594 // Lanchor:
1595 // adr x17, Lanchor ; compute target address
1596 // add x16, x17, x16
1597 // br x16 ; branch to target
1598
1599 MachineOperand JTOp = MI.getOperand(0);
1600
1601 unsigned JTI = JTOp.getIndex();
1602 assert(!AArch64FI->getJumpTableEntryPCRelSymbol(JTI) &&
1603 "unsupported compressed jump table");
1604
1605 const uint64_t NumTableEntries = JTs[JTI].MBBs.size();
1606
1607 // cmp only supports a 12-bit immediate. If we need more, materialize the
1608 // immediate, using x17 as a scratch register.
1609 uint64_t MaxTableEntry = NumTableEntries - 1;
1610 if (isUInt<12>(MaxTableEntry)) {
1611 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXri)
1612 .addReg(AArch64::XZR)
1613 .addReg(AArch64::X16)
1614 .addImm(MaxTableEntry)
1615 .addImm(0));
1616 } else {
1617 emitMOVZ(AArch64::X17, static_cast<uint16_t>(MaxTableEntry), 0);
1618 // It's sad that we have to manually materialize instructions, but we can't
1619 // trivially reuse the main pseudo expansion logic.
1620 // A MOVK sequence is easy enough to generate and handles the general case.
1621 for (int Offset = 16; Offset < 64; Offset += 16) {
1622 if ((MaxTableEntry >> Offset) == 0)
1623 break;
1624 emitMOVK(AArch64::X17, static_cast<uint16_t>(MaxTableEntry >> Offset),
1625 Offset);
1626 }
1627 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs)
1628 .addReg(AArch64::XZR)
1629 .addReg(AArch64::X16)
1630 .addReg(AArch64::X17)
1631 .addImm(0));
1632 }
1633
1634 // This picks entry #0 on failure.
1635 // We might want to trap instead.
1636 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CSELXr)
1637 .addReg(AArch64::X16)
1638 .addReg(AArch64::X16)
1639 .addReg(AArch64::XZR)
1640 .addImm(AArch64CC::LS));
1641
1642 // Prepare the @PAGE/@PAGEOFF low/high operands.
1643 MachineOperand JTMOHi(JTOp), JTMOLo(JTOp);
1644 MCOperand JTMCHi, JTMCLo;
1645
1646 JTMOHi.setTargetFlags(AArch64II::MO_PAGE);
1647 JTMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
1648
1649 MCInstLowering.lowerOperand(JTMOHi, JTMCHi);
1650 MCInstLowering.lowerOperand(JTMOLo, JTMCLo);
1651
1652 EmitToStreamer(
1653 *OutStreamer,
1654 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(JTMCHi));
1655
1656 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri)
1657 .addReg(AArch64::X17)
1658 .addReg(AArch64::X17)
1659 .addOperand(JTMCLo)
1660 .addImm(0));
1661
1662 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX)
1663 .addReg(AArch64::X16)
1664 .addReg(AArch64::X17)
1665 .addReg(AArch64::X16)
1666 .addImm(0)
1667 .addImm(1));
1668
1669 MCSymbol *AdrLabel = MF->getContext().createTempSymbol();
1670 const auto *AdrLabelE = MCSymbolRefExpr::create(AdrLabel, MF->getContext());
1671 AArch64FI->setJumpTableEntryInfo(JTI, 4, AdrLabel);
1672
1673 OutStreamer->emitLabel(AdrLabel);
1674 EmitToStreamer(
1675 *OutStreamer,
1676 MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addExpr(AdrLabelE));
1677
1678 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1679 .addReg(AArch64::X16)
1680 .addReg(AArch64::X17)
1681 .addReg(AArch64::X16)
1682 .addImm(0));
1683
1684 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
1685}
1686
1687void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer,
1688 const llvm::MachineInstr &MI) {
1689 unsigned Opcode = MI.getOpcode();
1690 assert(STI->hasMOPS());
1691 assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
1692
1693 const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
1694 if (Opcode == AArch64::MOPSMemoryCopyPseudo)
1695 return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
1696 if (Opcode == AArch64::MOPSMemoryMovePseudo)
1697 return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
1698 if (Opcode == AArch64::MOPSMemorySetPseudo)
1699 return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
1700 if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
1701 return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
1702 llvm_unreachable("Unhandled memory operation pseudo");
1703 }();
1704 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
1705 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
1706
1707 for (auto Op : Ops) {
1708 int i = 0;
1709 auto MCIB = MCInstBuilder(Op);
1710 // Destination registers
1711 MCIB.addReg(MI.getOperand(i++).getReg());
1712 MCIB.addReg(MI.getOperand(i++).getReg());
1713 if (!IsSet)
1714 MCIB.addReg(MI.getOperand(i++).getReg());
1715 // Input registers
1716 MCIB.addReg(MI.getOperand(i++).getReg());
1717 MCIB.addReg(MI.getOperand(i++).getReg());
1718 MCIB.addReg(MI.getOperand(i++).getReg());
1719
1720 EmitToStreamer(OutStreamer, MCIB);
1721 }
1722}
1723
1724void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1725 const MachineInstr &MI) {
1726 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
1727
1728 auto &Ctx = OutStreamer.getContext();
1729 MCSymbol *MILabel = Ctx.createTempSymbol();
1730 OutStreamer.emitLabel(MILabel);
1731
1732 SM.recordStackMap(*MILabel, MI);
1733 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1734
1735 // Scan ahead to trim the shadow.
1736 const MachineBasicBlock &MBB = *MI.getParent();
1738 ++MII;
1739 while (NumNOPBytes > 0) {
1740 if (MII == MBB.end() || MII->isCall() ||
1741 MII->getOpcode() == AArch64::DBG_VALUE ||
1742 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1743 MII->getOpcode() == TargetOpcode::STACKMAP)
1744 break;
1745 ++MII;
1746 NumNOPBytes -= 4;
1747 }
1748
1749 // Emit nops.
1750 for (unsigned i = 0; i < NumNOPBytes; i += 4)
1751 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::NOP));
1752}
1753
1754// Lower a patchpoint of the form:
1755// [<def>], <id>, <numBytes>, <target>, <numArgs>
1756void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1757 const MachineInstr &MI) {
1758 auto &Ctx = OutStreamer.getContext();
1759 MCSymbol *MILabel = Ctx.createTempSymbol();
1760 OutStreamer.emitLabel(MILabel);
1761 SM.recordPatchPoint(*MILabel, MI);
1762
1763 PatchPointOpers Opers(&MI);
1764
1765 int64_t CallTarget = Opers.getCallTarget().getImm();
1766 unsigned EncodedBytes = 0;
1767 if (CallTarget) {
1768 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
1769 "High 16 bits of call target should be zero.");
1770 Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
1771 EncodedBytes = 16;
1772 // Materialize the jump address:
1773 emitMOVZ(ScratchReg, (CallTarget >> 32) & 0xFFFF, 32);
1774 emitMOVK(ScratchReg, (CallTarget >> 16) & 0xFFFF, 16);
1775 emitMOVK(ScratchReg, CallTarget & 0xFFFF, 0);
1776 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
1777 }
1778 // Emit padding.
1779 unsigned NumBytes = Opers.getNumPatchBytes();
1780 assert(NumBytes >= EncodedBytes &&
1781 "Patchpoint can't request size less than the length of a call.");
1782 assert((NumBytes - EncodedBytes) % 4 == 0 &&
1783 "Invalid number of NOP bytes requested!");
1784 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
1785 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::NOP));
1786}
1787
1788void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1789 const MachineInstr &MI) {
1790 StatepointOpers SOpers(&MI);
1791 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1792 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1793 for (unsigned i = 0; i < PatchBytes; i += 4)
1794 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::NOP));
1795 } else {
1796 // Lower call target and choose correct opcode
1797 const MachineOperand &CallTarget = SOpers.getCallTarget();
1798 MCOperand CallTargetMCOp;
1799 unsigned CallOpcode;
1800 switch (CallTarget.getType()) {
1803 MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1804 CallOpcode = AArch64::BL;
1805 break;
1807 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
1808 CallOpcode = AArch64::BL;
1809 break;
1811 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
1812 CallOpcode = AArch64::BLR;
1813 break;
1814 default:
1815 llvm_unreachable("Unsupported operand type in statepoint call target");
1816 break;
1817 }
1818
1819 EmitToStreamer(OutStreamer,
1820 MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
1821 }
1822
1823 auto &Ctx = OutStreamer.getContext();
1824 MCSymbol *MILabel = Ctx.createTempSymbol();
1825 OutStreamer.emitLabel(MILabel);
1826 SM.recordStatepoint(*MILabel, MI);
1827}
1828
1829void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) {
1830 // FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>,
1831 // <opcode>, <operands>
1832
1833 Register DefRegister = FaultingMI.getOperand(0).getReg();
1835 static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm());
1836 MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol();
1837 unsigned Opcode = FaultingMI.getOperand(3).getImm();
1838 unsigned OperandsBeginIdx = 4;
1839
1840 auto &Ctx = OutStreamer->getContext();
1841 MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1842 OutStreamer->emitLabel(FaultingLabel);
1843
1844 assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!");
1845 FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1846
1847 MCInst MI;
1848 MI.setOpcode(Opcode);
1849
1850 if (DefRegister != (Register)0)
1851 MI.addOperand(MCOperand::createReg(DefRegister));
1852
1853 for (const MachineOperand &MO :
1854 llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) {
1855 MCOperand Dest;
1856 lowerOperand(MO, Dest);
1857 MI.addOperand(Dest);
1858 }
1859
1860 OutStreamer->AddComment("on-fault: " + HandlerLabel->getName());
1861 EmitToStreamer(MI);
1862}
1863
1864void AArch64AsmPrinter::emitMovXReg(Register Dest, Register Src) {
1865 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
1866 .addReg(Dest)
1867 .addReg(AArch64::XZR)
1868 .addReg(Src)
1869 .addImm(0));
1870}
1871
1872void AArch64AsmPrinter::emitMOVZ(Register Dest, uint64_t Imm, unsigned Shift) {
1873 bool Is64Bit = AArch64::GPR64RegClass.contains(Dest);
1874 EmitToStreamer(*OutStreamer,
1875 MCInstBuilder(Is64Bit ? AArch64::MOVZXi : AArch64::MOVZWi)
1876 .addReg(Dest)
1877 .addImm(Imm)
1878 .addImm(Shift));
1879}
1880
1881void AArch64AsmPrinter::emitMOVK(Register Dest, uint64_t Imm, unsigned Shift) {
1882 bool Is64Bit = AArch64::GPR64RegClass.contains(Dest);
1883 EmitToStreamer(*OutStreamer,
1884 MCInstBuilder(Is64Bit ? AArch64::MOVKXi : AArch64::MOVKWi)
1885 .addReg(Dest)
1886 .addReg(Dest)
1887 .addImm(Imm)
1888 .addImm(Shift));
1889}
1890
1891void AArch64AsmPrinter::emitAUT(AArch64PACKey::ID Key, Register Pointer,
1892 Register Disc) {
1893 bool IsZeroDisc = Disc == AArch64::XZR;
1894 unsigned Opcode = getAUTOpcodeForKey(Key, IsZeroDisc);
1895
1896 // autiza x16 ; if IsZeroDisc
1897 // autia x16, x17 ; if !IsZeroDisc
1898 MCInst AUTInst;
1899 AUTInst.setOpcode(Opcode);
1900 AUTInst.addOperand(MCOperand::createReg(Pointer));
1901 AUTInst.addOperand(MCOperand::createReg(Pointer));
1902 if (!IsZeroDisc)
1903 AUTInst.addOperand(MCOperand::createReg(Disc));
1904
1905 EmitToStreamer(AUTInst);
1906}
1907
1908void AArch64AsmPrinter::emitPAC(AArch64PACKey::ID Key, Register Pointer,
1909 Register Disc) {
1910 bool IsZeroDisc = Disc == AArch64::XZR;
1911 unsigned Opcode = getPACOpcodeForKey(Key, IsZeroDisc);
1912
1913 // paciza x16 ; if IsZeroDisc
1914 // pacia x16, x17 ; if !IsZeroDisc
1915 MCInst PACInst;
1916 PACInst.setOpcode(Opcode);
1917 PACInst.addOperand(MCOperand::createReg(Pointer));
1918 PACInst.addOperand(MCOperand::createReg(Pointer));
1919 if (!IsZeroDisc)
1920 PACInst.addOperand(MCOperand::createReg(Disc));
1921
1922 EmitToStreamer(PACInst);
1923}
1924
1925void AArch64AsmPrinter::emitBLRA(bool IsCall, AArch64PACKey::ID Key,
1926 Register Target, Register Disc) {
1927 bool IsZeroDisc = Disc == AArch64::XZR;
1928 unsigned Opcode = getBranchOpcodeForKey(IsCall, Key, IsZeroDisc);
1929
1930 // blraaz x16 ; if IsZeroDisc
1931 // blraa x16, x17 ; if !IsZeroDisc
1932 MCInst Inst;
1933 Inst.setOpcode(Opcode);
1934 Inst.addOperand(MCOperand::createReg(Target));
1935 if (!IsZeroDisc)
1936 Inst.addOperand(MCOperand::createReg(Disc));
1937 EmitToStreamer(Inst);
1938}
1939
1940void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
1941 Register DestReg = MI.getOperand(0).getReg();
1942 if (!STI->hasZeroCycleZeroingFPWorkaround() && STI->isNeonAvailable()) {
1943 if (STI->hasZeroCycleZeroingFPR64()) {
1944 // Convert H/S register to corresponding D register
1945 const AArch64RegisterInfo *TRI = STI->getRegisterInfo();
1946 if (AArch64::FPR16RegClass.contains(DestReg))
1947 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::hsub,
1948 &AArch64::FPR64RegClass);
1949 else if (AArch64::FPR32RegClass.contains(DestReg))
1950 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::ssub,
1951 &AArch64::FPR64RegClass);
1952 else
1953 assert(AArch64::FPR64RegClass.contains(DestReg));
1954
1955 MCInst MOVI;
1956 MOVI.setOpcode(AArch64::MOVID);
1957 MOVI.addOperand(MCOperand::createReg(DestReg));
1959 EmitToStreamer(*OutStreamer, MOVI);
1960 ++NumZCZeroingInstrsFPR;
1961 } else if (STI->hasZeroCycleZeroingFPR128()) {
1962 // Convert H/S/D register to corresponding Q register
1963 const AArch64RegisterInfo *TRI = STI->getRegisterInfo();
1964 if (AArch64::FPR16RegClass.contains(DestReg)) {
1965 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::hsub,
1966 &AArch64::FPR128RegClass);
1967 } else if (AArch64::FPR32RegClass.contains(DestReg)) {
1968 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::ssub,
1969 &AArch64::FPR128RegClass);
1970 } else {
1971 assert(AArch64::FPR64RegClass.contains(DestReg));
1972 DestReg = TRI->getMatchingSuperReg(DestReg, AArch64::dsub,
1973 &AArch64::FPR128RegClass);
1974 }
1975
1976 MCInst MOVI;
1977 MOVI.setOpcode(AArch64::MOVIv2d_ns);
1978 MOVI.addOperand(MCOperand::createReg(DestReg));
1980 EmitToStreamer(*OutStreamer, MOVI);
1981 ++NumZCZeroingInstrsFPR;
1982 } else {
1983 emitFMov0AsFMov(MI, DestReg);
1984 }
1985 } else {
1986 emitFMov0AsFMov(MI, DestReg);
1987 }
1988}
1989
1990void AArch64AsmPrinter::emitFMov0AsFMov(const MachineInstr &MI,
1991 Register DestReg) {
1992 MCInst FMov;
1993 switch (MI.getOpcode()) {
1994 default:
1995 llvm_unreachable("Unexpected opcode");
1996 case AArch64::FMOVH0:
1997 FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
1998 if (!STI->hasFullFP16())
1999 DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
2000 FMov.addOperand(MCOperand::createReg(DestReg));
2001 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
2002 break;
2003 case AArch64::FMOVS0:
2004 FMov.setOpcode(AArch64::FMOVWSr);
2005 FMov.addOperand(MCOperand::createReg(DestReg));
2006 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
2007 break;
2008 case AArch64::FMOVD0:
2009 FMov.setOpcode(AArch64::FMOVXDr);
2010 FMov.addOperand(MCOperand::createReg(DestReg));
2011 FMov.addOperand(MCOperand::createReg(AArch64::XZR));
2012 break;
2013 }
2014 EmitToStreamer(*OutStreamer, FMov);
2015}
2016
2017Register AArch64AsmPrinter::emitPtrauthDiscriminator(uint64_t Disc,
2018 Register AddrDisc,
2019 Register ScratchReg,
2020 bool MayClobberAddrDisc) {
2021 assert(isPtrauthRegSafe(ScratchReg) &&
2022 "Safe scratch register must be provided by the caller");
2023 assert(isUInt<16>(Disc) && "Constant discriminator is too wide");
2024
2025 // So far we've used NoRegister in pseudos. Now we need real encodings.
2026 if (AddrDisc == AArch64::NoRegister)
2027 AddrDisc = AArch64::XZR;
2028
2029 // If there is no constant discriminator, there's no blend involved:
2030 // just use the address discriminator register as-is (XZR or not).
2031 if (!Disc)
2032 return AddrDisc;
2033
2034 // If there's only a constant discriminator, MOV it into the scratch register.
2035 if (AddrDisc == AArch64::XZR) {
2036 emitMOVZ(ScratchReg, Disc, 0);
2037 return ScratchReg;
2038 }
2039
2040 // If there are both, emit a blend into the scratch register.
2041
2042 // Check if we can save one MOV instruction.
2043 if (MayClobberAddrDisc && isPtrauthRegSafe(AddrDisc)) {
2044 ScratchReg = AddrDisc;
2045 } else {
2046 emitMovXReg(ScratchReg, AddrDisc);
2047 assert(ScratchReg != AddrDisc &&
2048 "Forbidden to clobber AddrDisc, but have to");
2049 }
2050
2051 emitMOVK(ScratchReg, Disc, 48);
2052 return ScratchReg;
2053}
2054
2055/// Emit a code sequence to check an authenticated pointer value.
2056///
2057/// This function emits a sequence of instructions that checks if TestedReg was
2058/// authenticated successfully. On success, execution continues at the next
2059/// instruction after the sequence.
2060///
2061/// The action performed on failure depends on the OnFailure argument:
2062/// * if OnFailure is not nullptr, control is transferred to that label after
2063/// clearing the PAC field
2064/// * otherwise, BRK instruction is emitted to generate an error
2065void AArch64AsmPrinter::emitPtrauthCheckAuthenticatedValue(
2066 Register TestedReg, Register ScratchReg, AArch64PACKey::ID Key,
2067 AArch64PAuth::AuthCheckMethod Method, const MCSymbol *OnFailure) {
2068 // Insert a sequence to check if authentication of TestedReg succeeded,
2069 // such as:
2070 //
2071 // - checked and clearing:
2072 // ; x16 is TestedReg, x17 is ScratchReg
2073 // mov x17, x16
2074 // xpaci x17
2075 // cmp x16, x17
2076 // b.eq Lsuccess
2077 // mov x16, x17
2078 // b Lend
2079 // Lsuccess:
2080 // ; skipped if authentication failed
2081 // Lend:
2082 // ...
2083 //
2084 // - checked and trapping:
2085 // mov x17, x16
2086 // xpaci x17
2087 // cmp x16, x17
2088 // b.eq Lsuccess
2089 // brk #<0xc470 + aut key>
2090 // Lsuccess:
2091 // ...
2092 //
2093 // See the documentation on AuthCheckMethod enumeration constants for
2094 // the specific code sequences that can be used to perform the check.
2096
2097 if (Method == AuthCheckMethod::None)
2098 return;
2099 if (Method == AuthCheckMethod::DummyLoad) {
2100 EmitToStreamer(MCInstBuilder(AArch64::LDRWui)
2101 .addReg(getWRegFromXReg(ScratchReg))
2102 .addReg(TestedReg)
2103 .addImm(0));
2104 assert(!OnFailure && "DummyLoad always traps on error");
2105 return;
2106 }
2107
2108 MCSymbol *SuccessSym = createTempSymbol("auth_success_");
2109 if (Method == AuthCheckMethod::XPAC || Method == AuthCheckMethod::XPACHint) {
2110 // mov Xscratch, Xtested
2111 emitMovXReg(ScratchReg, TestedReg);
2112
2113 if (Method == AuthCheckMethod::XPAC) {
2114 // xpac(i|d) Xscratch
2115 unsigned XPACOpc = getXPACOpcodeForKey(Key);
2116 EmitToStreamer(
2117 MCInstBuilder(XPACOpc).addReg(ScratchReg).addReg(ScratchReg));
2118 } else {
2119 // xpaclri
2120
2121 // Note that this method applies XPAC to TestedReg instead of ScratchReg.
2122 assert(TestedReg == AArch64::LR &&
2123 "XPACHint mode is only compatible with checking the LR register");
2125 "XPACHint mode is only compatible with I-keys");
2126 EmitToStreamer(MCInstBuilder(AArch64::XPACLRI));
2127 }
2128
2129 // cmp Xtested, Xscratch
2130 EmitToStreamer(MCInstBuilder(AArch64::SUBSXrs)
2131 .addReg(AArch64::XZR)
2132 .addReg(TestedReg)
2133 .addReg(ScratchReg)
2134 .addImm(0));
2135
2136 // b.eq Lsuccess
2137 EmitToStreamer(
2138 MCInstBuilder(AArch64::Bcc)
2139 .addImm(AArch64CC::EQ)
2140 .addExpr(MCSymbolRefExpr::create(SuccessSym, OutContext)));
2141 } else if (Method == AuthCheckMethod::HighBitsNoTBI) {
2142 // eor Xscratch, Xtested, Xtested, lsl #1
2143 EmitToStreamer(MCInstBuilder(AArch64::EORXrs)
2144 .addReg(ScratchReg)
2145 .addReg(TestedReg)
2146 .addReg(TestedReg)
2147 .addImm(1));
2148 // tbz Xscratch, #62, Lsuccess
2149 EmitToStreamer(
2150 MCInstBuilder(AArch64::TBZX)
2151 .addReg(ScratchReg)
2152 .addImm(62)
2153 .addExpr(MCSymbolRefExpr::create(SuccessSym, OutContext)));
2154 } else {
2155 llvm_unreachable("Unsupported check method");
2156 }
2157
2158 if (!OnFailure) {
2159 // Trapping sequences do a 'brk'.
2160 // brk #<0xc470 + aut key>
2161 EmitToStreamer(MCInstBuilder(AArch64::BRK).addImm(0xc470 | Key));
2162 } else {
2163 // Non-trapping checked sequences return the stripped result in TestedReg,
2164 // skipping over success-only code (such as re-signing the pointer) by
2165 // jumping to OnFailure label.
2166 // Note that this can introduce an authentication oracle (such as based on
2167 // the high bits of the re-signed value).
2168
2169 // FIXME: The XPAC method can be optimized by applying XPAC to TestedReg
2170 // instead of ScratchReg, thus eliminating one `mov` instruction.
2171 // Both XPAC and XPACHint can be further optimized by not using a
2172 // conditional branch jumping over an unconditional one.
2173
2174 switch (Method) {
2175 case AuthCheckMethod::XPACHint:
2176 // LR is already XPAC-ed at this point.
2177 break;
2178 case AuthCheckMethod::XPAC:
2179 // mov Xtested, Xscratch
2180 emitMovXReg(TestedReg, ScratchReg);
2181 break;
2182 default:
2183 // If Xtested was not XPAC-ed so far, emit XPAC here.
2184 // xpac(i|d) Xtested
2185 unsigned XPACOpc = getXPACOpcodeForKey(Key);
2186 EmitToStreamer(
2187 MCInstBuilder(XPACOpc).addReg(TestedReg).addReg(TestedReg));
2188 }
2189
2190 // b Lend
2191 const auto *OnFailureExpr = MCSymbolRefExpr::create(OnFailure, OutContext);
2192 EmitToStreamer(MCInstBuilder(AArch64::B).addExpr(OnFailureExpr));
2193 }
2194
2195 // If the auth check succeeds, we can continue.
2196 // Lsuccess:
2197 OutStreamer->emitLabel(SuccessSym);
2198}
2199
2200// With Pointer Authentication, it may be needed to explicitly check the
2201// authenticated value in LR before performing a tail call.
2202// Otherwise, the callee may re-sign the invalid return address,
2203// introducing a signing oracle.
2204void AArch64AsmPrinter::emitPtrauthTailCallHardening(const MachineInstr *TC) {
2205 if (!AArch64FI->shouldSignReturnAddress(*MF))
2206 return;
2207
2208 auto LRCheckMethod = STI->getAuthenticatedLRCheckMethod(*MF);
2209 if (LRCheckMethod == AArch64PAuth::AuthCheckMethod::None)
2210 return;
2211
2212 const AArch64RegisterInfo *TRI = STI->getRegisterInfo();
2213 Register ScratchReg =
2214 TC->readsRegister(AArch64::X16, TRI) ? AArch64::X17 : AArch64::X16;
2215 assert(!TC->readsRegister(ScratchReg, TRI) &&
2216 "Neither x16 nor x17 is available as a scratch register");
2219 emitPtrauthCheckAuthenticatedValue(AArch64::LR, ScratchReg, Key,
2220 LRCheckMethod);
2221}
2222
2223bool AArch64AsmPrinter::emitDeactivationSymbolRelocation(Value *DS) {
2224 if (!DS)
2225 return false;
2226
2227 if (isa<GlobalAlias>(DS)) {
2228 // Just emit the nop directly.
2229 EmitToStreamer(MCInstBuilder(AArch64::NOP));
2230 return true;
2231 }
2232 MCSymbol *Dot = OutContext.createTempSymbol();
2233 OutStreamer->emitLabel(Dot);
2234 const MCExpr *DeactDotExpr = MCSymbolRefExpr::create(Dot, OutContext);
2235
2236 const MCExpr *DSExpr = MCSymbolRefExpr::create(
2237 OutContext.getOrCreateSymbol(DS->getName()), OutContext);
2238 OutStreamer->emitRelocDirective(*DeactDotExpr, "R_AARCH64_PATCHINST", DSExpr,
2239 SMLoc());
2240 return false;
2241}
2242
2243AArch64AsmPrinter::PtrAuthSchema::PtrAuthSchema(
2244 AArch64PACKey::ID Key, uint64_t IntDisc, const MachineOperand &AddrDiscOp)
2245 : Key(Key), IntDisc(IntDisc), AddrDisc(AddrDiscOp.getReg()),
2246 AddrDiscIsKilled(AddrDiscOp.isKill()) {}
2247
2248void AArch64AsmPrinter::emitPtrauthApplyIndirectAddend(Register Pointer,
2249 Register Scratch,
2250 int64_t Addend) {
2251 if (isInt<9>(Addend)) {
2252 // ldrsw Scratch, [Pointer, #Addend]! ; note: Pointer+Addend is used later.
2253 EmitToStreamer(MCInstBuilder(AArch64::LDRSWpre)
2254 .addReg(Pointer)
2255 .addReg(Scratch)
2256 .addReg(Pointer)
2257 .addImm(/*simm9:*/ Addend));
2258 } else {
2259 // Pointer += Addend computation has 2 variants
2260 if (isUInt<24>(Addend)) {
2261 // Variant 1: add Pointer, Pointer, (Addend >> shift12) lsl shift12
2262 // This can take up to 2 instructions.
2263 for (int BitPos = 0; BitPos != 24 && (Addend >> BitPos); BitPos += 12) {
2264 EmitToStreamer(
2265 MCInstBuilder(AArch64::ADDXri)
2266 .addReg(Pointer)
2267 .addReg(Pointer)
2268 .addImm((Addend >> BitPos) & 0xfff)
2269 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
2270 }
2271 } else {
2272 // Variant 2: accumulate constant in Scratch 16 bits at a time,
2273 // and add it to Pointer. This can take 2-5 instructions.
2274 emitMOVZ(Scratch, Addend & 0xffff, 0);
2275 for (int Offset = 16; Offset < 64; Offset += 16) {
2276 if (unsigned Fragment = (Addend >> Offset) & 0xffff)
2277 emitMOVK(Scratch, Fragment, Offset);
2278 }
2279
2280 // add Pointer, Pointer, Scratch
2281 EmitToStreamer(MCInstBuilder(AArch64::ADDXrs)
2282 .addReg(Pointer)
2283 .addReg(Pointer)
2284 .addReg(Scratch)
2285 .addImm(0));
2286 }
2287 // ldrsw Scratch, [Pointer]
2288 EmitToStreamer(MCInstBuilder(AArch64::LDRSWui)
2289 .addReg(Scratch)
2290 .addReg(Pointer)
2291 .addImm(0));
2292 }
2293 // add Pointer, Pointer, Scratch
2294 EmitToStreamer(MCInstBuilder(AArch64::ADDXrs)
2295 .addReg(Pointer)
2296 .addReg(Pointer)
2297 .addReg(Scratch)
2298 .addImm(0));
2299}
2300
2301void AArch64AsmPrinter::emitPtrauthAuthResign(
2302 Register Pointer, Register Scratch, PtrAuthSchema AuthSchema,
2303 std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend,
2304 Value *DS) {
2305 const bool IsResign = SignSchema.has_value();
2306 // We expand AUT/AUTPAC into a sequence of the form
2307 //
2308 // ; authenticate x16
2309 // ; check pointer in x16
2310 // Lsuccess:
2311 // ; sign x16 (if AUTPAC)
2312 // Lend: ; if not trapping on failure
2313 //
2314 // with the checking sequence chosen depending on whether/how we should check
2315 // the pointer and whether we should trap on failure.
2316
2317 // By default, auth/resign sequences check for auth failures.
2318 bool ShouldCheck = true;
2319 // In the checked sequence, we only trap if explicitly requested.
2320 bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps");
2321
2322 // On an FPAC CPU, you get traps whether you want them or not: there's
2323 // no point in emitting checks or traps.
2324 if (STI->hasFPAC())
2325 ShouldCheck = ShouldTrap = false;
2326
2327 // However, command-line flags can override this, for experimentation.
2328 switch (PtrauthAuthChecks) {
2330 break;
2332 ShouldCheck = ShouldTrap = false;
2333 break;
2335 ShouldCheck = true;
2336 ShouldTrap = false;
2337 break;
2339 ShouldCheck = ShouldTrap = true;
2340 break;
2341 }
2342
2343 // Compute aut discriminator
2344 Register AUTDiscReg =
2345 emitPtrauthDiscriminator(AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch,
2346 AuthSchema.AddrDiscIsKilled);
2347
2348 if (!emitDeactivationSymbolRelocation(DS))
2349 emitAUT(AuthSchema.Key, Pointer, AUTDiscReg);
2350
2351 // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done.
2352 if (!IsResign && (!ShouldCheck || !ShouldTrap))
2353 return;
2354
2355 MCSymbol *EndSym = nullptr;
2356
2357 if (ShouldCheck) {
2358 if (IsResign && !ShouldTrap)
2359 EndSym = createTempSymbol("resign_end_");
2360
2361 emitPtrauthCheckAuthenticatedValue(Pointer, Scratch, AuthSchema.Key,
2362 AArch64PAuth::AuthCheckMethod::XPAC,
2363 EndSym);
2364 }
2365
2366 // We already emitted unchecked and checked-but-non-trapping AUTs.
2367 // That left us with trapping AUTs, and AUTPA/AUTRELLOADPACs.
2368 // Trapping AUTs don't need PAC: we're done.
2369 if (!IsResign)
2370 return;
2371
2372 if (Addend.has_value())
2373 emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend);
2374
2375 // Compute pac discriminator into x17
2376 Register PACDiscReg = emitPtrauthDiscriminator(SignSchema->IntDisc,
2377 SignSchema->AddrDisc, Scratch);
2378 emitPAC(SignSchema->Key, Pointer, PACDiscReg);
2379
2380 // Lend:
2381 if (EndSym)
2382 OutStreamer->emitLabel(EndSym);
2383}
2384
2385void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) {
2386 Register Val = MI->getOperand(1).getReg();
2387 auto Key = (AArch64PACKey::ID)MI->getOperand(2).getImm();
2388 uint64_t Disc = MI->getOperand(3).getImm();
2389 Register AddrDisc = MI->getOperand(4).getReg();
2390 bool AddrDiscKilled = MI->getOperand(4).isKill();
2391
2392 // As long as at least one of Val and AddrDisc is in GPR64noip, a scratch
2393 // register is available.
2394 Register ScratchReg = Val == AArch64::X16 ? AArch64::X17 : AArch64::X16;
2395 assert(ScratchReg != AddrDisc &&
2396 "Neither X16 nor X17 is available as a scratch register");
2397
2398 // Compute pac discriminator
2399 Register DiscReg = emitPtrauthDiscriminator(
2400 Disc, AddrDisc, ScratchReg, /*MayClobberAddrDisc=*/AddrDiscKilled);
2401
2402 if (emitDeactivationSymbolRelocation(MI->getDeactivationSymbol()))
2403 return;
2404
2405 emitPAC(Key, Val, DiscReg);
2406}
2407
2408void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
2409 bool IsCall = MI->getOpcode() == AArch64::BLRA;
2410 unsigned BrTarget = MI->getOperand(0).getReg();
2411
2412 auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm();
2413 uint64_t Disc = MI->getOperand(2).getImm();
2414
2415 unsigned AddrDisc = MI->getOperand(3).getReg();
2416
2417 // Make sure AddrDisc is solely used to compute the discriminator.
2418 // While hardly meaningful, it is still possible to describe an authentication
2419 // of a pointer against its own value (instead of storage address) with
2420 // intrinsics, so use report_fatal_error instead of assert.
2421 if (BrTarget == AddrDisc)
2422 report_fatal_error("Branch target is signed with its own value");
2423
2424 // If we are printing BLRA pseudo, try to save one MOV by making use of the
2425 // fact that x16 and x17 are described as clobbered by the MI instruction and
2426 // AddrDisc is not used as any other input.
2427 //
2428 // Back in the day, emitPtrauthDiscriminator was restricted to only returning
2429 // either x16 or x17, meaning the returned register is always among the
2430 // implicit-def'ed registers of BLRA pseudo. Now this property can be violated
2431 // if isX16X17Safer predicate is false, thus manually check if AddrDisc is
2432 // among x16 and x17 to prevent clobbering unexpected registers.
2433 //
2434 // Unlike BLRA, BRA pseudo is used to perform computed goto, and thus not
2435 // declared as clobbering x16/x17.
2436 //
2437 // FIXME: Make use of `killed` flags and register masks instead.
2438 bool AddrDiscIsImplicitDef =
2439 IsCall && (AddrDisc == AArch64::X16 || AddrDisc == AArch64::X17);
2440 Register DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, AArch64::X17,
2441 AddrDiscIsImplicitDef);
2442 emitBLRA(IsCall, Key, BrTarget, DiscReg);
2443}
2444
2445void AArch64AsmPrinter::emitAddImm(MCRegister Reg, int64_t Addend,
2446 MCRegister Tmp) {
2447 if (Addend != 0) {
2448 const uint64_t AbsOffset = (Addend > 0 ? Addend : -((uint64_t)Addend));
2449 const bool IsNeg = Addend < 0;
2450 if (isUInt<24>(AbsOffset)) {
2451 for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
2452 BitPos += 12) {
2453 EmitToStreamer(
2454 MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri)
2455 .addReg(Reg)
2456 .addReg(Reg)
2457 .addImm((AbsOffset >> BitPos) & 0xfff)
2458 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
2459 }
2460 } else {
2461 const uint64_t UAddend = Addend;
2462 EmitToStreamer(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
2463 .addReg(Tmp)
2464 .addImm((IsNeg ? ~UAddend : UAddend) & 0xffff)
2465 .addImm(/*shift=*/0));
2466 auto NeedMovk = [IsNeg, UAddend](int BitPos) -> bool {
2467 assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
2468 uint64_t Shifted = UAddend >> BitPos;
2469 if (!IsNeg)
2470 return Shifted != 0;
2471 for (int I = 0; I != 64 - BitPos; I += 16)
2472 if (((Shifted >> I) & 0xffff) != 0xffff)
2473 return true;
2474 return false;
2475 };
2476 for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16)
2477 emitMOVK(Tmp, (UAddend >> BitPos) & 0xffff, BitPos);
2478
2479 EmitToStreamer(MCInstBuilder(AArch64::ADDXrs)
2480 .addReg(Reg)
2481 .addReg(Reg)
2482 .addReg(Tmp)
2483 .addImm(/*shift=*/0));
2484 }
2485 }
2486}
2487
2488void AArch64AsmPrinter::emitAddress(MCRegister Reg, const MCExpr *Expr,
2489 MCRegister Tmp, bool DSOLocal,
2490 const MCSubtargetInfo &STI) {
2491 MCValue Val;
2492 if (!Expr->evaluateAsRelocatable(Val, nullptr))
2493 report_fatal_error("emitAddress could not evaluate");
2494 if (DSOLocal) {
2495 EmitToStreamer(
2496 MCInstBuilder(AArch64::ADRP)
2497 .addReg(Reg)
2499 OutStreamer->getContext())));
2500 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
2501 .addReg(Reg)
2502 .addReg(Reg)
2503 .addExpr(MCSpecifierExpr::create(
2504 Expr, AArch64::S_LO12, OutStreamer->getContext()))
2505 .addImm(0));
2506 } else {
2507 auto *SymRef =
2508 MCSymbolRefExpr::create(Val.getAddSym(), OutStreamer->getContext());
2509 EmitToStreamer(
2510 MCInstBuilder(AArch64::ADRP)
2511 .addReg(Reg)
2513 OutStreamer->getContext())));
2514 EmitToStreamer(
2515 MCInstBuilder(AArch64::LDRXui)
2516 .addReg(Reg)
2517 .addReg(Reg)
2519 OutStreamer->getContext())));
2520 emitAddImm(Reg, Val.getConstant(), Tmp);
2521 }
2522}
2523
2525 // IFUNCs are ELF-only.
2526 if (!TT.isOSBinFormatELF())
2527 return false;
2528
2529 // IFUNCs are supported on glibc, bionic, and some but not all of the BSDs.
2530 return TT.isOSGlibc() || TT.isAndroid() || TT.isOSFreeBSD() ||
2531 TT.isOSDragonFly() || TT.isOSNetBSD();
2532}
2533
2534// Emit an ifunc resolver that returns a signed pointer to the specified target,
2535// and return a FUNCINIT reference to the resolver. In the linked binary, this
2536// function becomes the target of an IRELATIVE relocation. This resolver is used
2537// to relocate signed pointers in global variable initializers in special cases
2538// where the standard R_AARCH64_AUTH_ABS64 relocation would not work.
2539//
2540// Example (signed null pointer, not address discriminated):
2541//
2542// .8byte .Lpauth_ifunc0
2543// .pushsection .text.startup,"ax",@progbits
2544// .Lpauth_ifunc0:
2545// mov x0, #0
2546// mov x1, #12345
2547// b __emupac_pacda
2548//
2549// Example (signed null pointer, address discriminated):
2550//
2551// .Ltmp:
2552// .8byte .Lpauth_ifunc0
2553// .pushsection .text.startup,"ax",@progbits
2554// .Lpauth_ifunc0:
2555// mov x0, #0
2556// adrp x1, .Ltmp
2557// add x1, x1, :lo12:.Ltmp
2558// b __emupac_pacda
2559// .popsection
2560//
2561// Example (signed pointer to symbol, not address discriminated):
2562//
2563// .Ltmp:
2564// .8byte .Lpauth_ifunc0
2565// .pushsection .text.startup,"ax",@progbits
2566// .Lpauth_ifunc0:
2567// adrp x0, symbol
2568// add x0, x0, :lo12:symbol
2569// mov x1, #12345
2570// b __emupac_pacda
2571// .popsection
2572//
2573// Example (signed null pointer, not address discriminated, with deactivation
2574// symbol ds):
2575//
2576// .8byte .Lpauth_ifunc0
2577// .pushsection .text.startup,"ax",@progbits
2578// .Lpauth_ifunc0:
2579// mov x0, #0
2580// mov x1, #12345
2581// .reloc ., R_AARCH64_PATCHINST, ds
2582// b __emupac_pacda
2583// ret
2584// .popsection
2585const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative(
2586 const MCExpr *Target, uint64_t Disc, AArch64PACKey::ID KeyID,
2587 bool HasAddressDiversity, bool IsDSOLocal, const MCExpr *DSExpr) {
2588 const Triple &TT = TM.getTargetTriple();
2589
2590 // We only emit an IRELATIVE relocation if the target supports IRELATIVE.
2592 return nullptr;
2593
2594 // For now, only the DA key is supported.
2595 if (KeyID != AArch64PACKey::DA)
2596 return nullptr;
2597
2598 // AArch64Subtarget is huge, so heap allocate it so we don't run out of stack
2599 // space.
2600 auto STI = std::make_unique<AArch64Subtarget>(
2601 TT, TM.getTargetCPU(), TM.getTargetCPU(), TM.getTargetFeatureString(), TM,
2602 true);
2603 this->STI = STI.get();
2604
2605 MCSymbol *Place = OutStreamer->getContext().createTempSymbol();
2606 OutStreamer->emitLabel(Place);
2607 OutStreamer->pushSection();
2608
2609 const MCSymbolELF *Group =
2610 static_cast<MCSectionELF *>(OutStreamer->getCurrentSectionOnly())
2611 ->getGroup();
2613 if (Group)
2615 OutStreamer->switchSection(OutStreamer->getContext().getELFSection(
2616 ".text.startup", ELF::SHT_PROGBITS, Flags, 0, Group, true,
2617 Group ? MCSection::NonUniqueID : PAuthIFuncNextUniqueID++, nullptr));
2618
2619 MCSymbol *IRelativeSym =
2620 OutStreamer->getContext().createLinkerPrivateSymbol("pauth_ifunc");
2621 OutStreamer->emitLabel(IRelativeSym);
2622 if (isa<MCConstantExpr>(Target)) {
2623 OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
2624 .addReg(AArch64::X0)
2625 .addExpr(Target)
2626 .addImm(0),
2627 *STI);
2628 } else {
2629 emitAddress(AArch64::X0, Target, AArch64::X16, IsDSOLocal, *STI);
2630 }
2631 if (HasAddressDiversity) {
2632 auto *PlacePlusDisc = MCBinaryExpr::createAdd(
2633 MCSymbolRefExpr::create(Place, OutStreamer->getContext()),
2634 MCConstantExpr::create(Disc, OutStreamer->getContext()),
2635 OutStreamer->getContext());
2636 emitAddress(AArch64::X1, PlacePlusDisc, AArch64::X16, /*IsDSOLocal=*/true,
2637 *STI);
2638 } else {
2639 if (!isUInt<16>(Disc)) {
2640 OutContext.reportError(SMLoc(), "AArch64 PAC Discriminator '" +
2641 Twine(Disc) +
2642 "' out of range [0, 0xFFFF]");
2643 }
2644 emitMOVZ(AArch64::X1, Disc, 0);
2645 }
2646
2647 if (DSExpr) {
2648 MCSymbol *PrePACInst = OutStreamer->getContext().createTempSymbol();
2649 OutStreamer->emitLabel(PrePACInst);
2650
2651 auto *PrePACInstExpr =
2652 MCSymbolRefExpr::create(PrePACInst, OutStreamer->getContext());
2653 OutStreamer->emitRelocDirective(*PrePACInstExpr, "R_AARCH64_PATCHINST",
2654 DSExpr, SMLoc());
2655 }
2656
2657 // We don't know the subtarget because this is being emitted for a global
2658 // initializer. Because the performance of IFUNC resolvers is unimportant, we
2659 // always call the EmuPAC runtime, which will end up using the PAC instruction
2660 // if the target supports PAC.
2661 MCSymbol *EmuPAC =
2662 OutStreamer->getContext().getOrCreateSymbol("__emupac_pacda");
2663 const MCSymbolRefExpr *EmuPACRef =
2664 MCSymbolRefExpr::create(EmuPAC, OutStreamer->getContext());
2665 OutStreamer->emitInstruction(MCInstBuilder(AArch64::B).addExpr(EmuPACRef),
2666 *STI);
2667
2668 // We need a RET despite the above tail call because the deactivation symbol
2669 // may replace the tail call with a NOP.
2670 if (DSExpr)
2671 OutStreamer->emitInstruction(
2672 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
2673 OutStreamer->popSection();
2674
2676 MCSymbolRefExpr::create(IRelativeSym, OutStreamer->getContext()),
2677 AArch64::S_FUNCINIT, OutStreamer->getContext());
2678}
2679
2680const MCExpr *
2681AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2682 MCContext &Ctx = OutContext;
2683
2684 // Figure out the base symbol and the addend, if any.
2685 APInt Offset(64, 0);
2686 const Value *BaseGV = CPA.getPointer()->stripAndAccumulateConstantOffsets(
2687 getDataLayout(), Offset, /*AllowNonInbounds=*/true);
2688
2689 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
2690
2691 const MCExpr *Sym;
2692 if (BaseGVB) {
2693 // If there is an addend, turn that into the appropriate MCExpr.
2694 Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2695 if (Offset.sgt(0))
2697 Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2698 else if (Offset.slt(0))
2700 Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2701 } else if (isa<ConstantPointerNull>(BaseGV)) {
2702 Sym = MCConstantExpr::create(Offset.getSExtValue(), Ctx);
2703 } else {
2704 reportFatalUsageError("unsupported constant expression in ptrauth pointer");
2705 }
2706
2707 const MCExpr *DSExpr = nullptr;
2708 if (auto *DS = dyn_cast<GlobalValue>(CPA.getDeactivationSymbol())) {
2709 if (isa<GlobalAlias>(DS))
2710 return Sym;
2711 DSExpr = MCSymbolRefExpr::create(getSymbol(DS), Ctx);
2712 }
2713
2714 uint64_t KeyID = CPA.getKey()->getZExtValue();
2715 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
2716 // AArch64AuthMCExpr::printImpl, so fail fast.
2717 if (KeyID > AArch64PACKey::LAST) {
2718 CPA.getContext().emitError("AArch64 PAC Key ID '" + Twine(KeyID) +
2719 "' out of range [0, " +
2720 Twine((unsigned)AArch64PACKey::LAST) + "]");
2721 KeyID = 0;
2722 }
2723
2724 uint64_t Disc = CPA.getDiscriminator()->getZExtValue();
2725
2726 // Check if we can represent this with an IRELATIVE and emit it if so.
2727 if (auto *IFuncSym = emitPAuthRelocationAsIRelative(
2728 Sym, Disc, AArch64PACKey::ID(KeyID), CPA.hasAddressDiscriminator(),
2729 BaseGVB && BaseGVB->isDSOLocal(), DSExpr))
2730 return IFuncSym;
2731
2732 if (!isUInt<16>(Disc)) {
2733 CPA.getContext().emitError("AArch64 PAC Discriminator '" + Twine(Disc) +
2734 "' out of range [0, 0xFFFF]");
2735 Disc = 0;
2736 }
2737
2738 if (DSExpr)
2739 report_fatal_error("deactivation symbols unsupported in constant "
2740 "expressions on this target");
2741
2742 // Finally build the complete @AUTH expr.
2743 return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
2744 CPA.hasAddressDiscriminator(), Ctx);
2745}
2746
2747void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
2748 unsigned DstReg = MI.getOperand(0).getReg();
2749 const MachineOperand &GAOp = MI.getOperand(1);
2750 const uint64_t KeyC = MI.getOperand(2).getImm();
2751 assert(KeyC <= AArch64PACKey::LAST &&
2752 "key is out of range [0, AArch64PACKey::LAST]");
2753 const auto Key = (AArch64PACKey::ID)KeyC;
2754 const uint64_t Disc = MI.getOperand(3).getImm();
2755 assert(isUInt<16>(Disc) &&
2756 "constant discriminator is out of range [0, 0xffff]");
2757
2758 // Emit instruction sequence like the following:
2759 // ADRP x16, symbol$auth_ptr$key$disc
2760 // LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc]
2761 //
2762 // Where the $auth_ptr$ symbol is the stub slot containing the signed pointer
2763 // to symbol.
2764 MCSymbol *AuthPtrStubSym;
2765 if (TM.getTargetTriple().isOSBinFormatELF()) {
2766 const auto &TLOF =
2767 static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering());
2768
2769 assert(GAOp.getOffset() == 0 &&
2770 "non-zero offset for $auth_ptr$ stub slots is not supported");
2771 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
2772 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
2773 } else {
2774 assert(TM.getTargetTriple().isOSBinFormatMachO() &&
2775 "LOADauthptrstatic is implemented only for MachO/ELF");
2776
2777 const auto &TLOF = static_cast<const AArch64_MachoTargetObjectFile &>(
2778 getObjFileLowering());
2779
2780 assert(GAOp.getOffset() == 0 &&
2781 "non-zero offset for $auth_ptr$ stub slots is not supported");
2782 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
2783 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
2784 }
2785
2786 MachineOperand StubMOHi =
2788 MachineOperand StubMOLo = MachineOperand::CreateMCSymbol(
2789 AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2790 MCOperand StubMCHi, StubMCLo;
2791
2792 MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
2793 MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
2794
2795 EmitToStreamer(
2796 *OutStreamer,
2797 MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi));
2798
2799 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui)
2800 .addReg(DstReg)
2801 .addReg(DstReg)
2802 .addOperand(StubMCLo));
2803}
2804
2805void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2806 const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC;
2807 const bool IsELFSignedGOT = MI.getParent()
2808 ->getParent()
2809 ->getInfo<AArch64FunctionInfo>()
2810 ->hasELFSignedGOT();
2811 MachineOperand GAOp = MI.getOperand(0);
2812 const uint64_t KeyC = MI.getOperand(1).getImm();
2813 assert(KeyC <= AArch64PACKey::LAST &&
2814 "key is out of range [0, AArch64PACKey::LAST]");
2815 const auto Key = (AArch64PACKey::ID)KeyC;
2816 const unsigned AddrDisc = MI.getOperand(2).getReg();
2817 const uint64_t Disc = MI.getOperand(3).getImm();
2818
2819 const int64_t Offset = GAOp.getOffset();
2820 GAOp.setOffset(0);
2821
2822 // Emit:
2823 // target materialization:
2824 // - via GOT:
2825 // - unsigned GOT:
2826 // adrp x16, :got:target
2827 // ldr x16, [x16, :got_lo12:target]
2828 // add offset to x16 if offset != 0
2829 // - ELF signed GOT:
2830 // adrp x17, :got:target
2831 // add x17, x17, :got_auth_lo12:target
2832 // ldr x16, [x17]
2833 // aut{i|d}a x16, x17
2834 // check+trap sequence (if no FPAC)
2835 // add offset to x16 if offset != 0
2836 //
2837 // - direct:
2838 // adrp x16, target
2839 // add x16, x16, :lo12:target
2840 // add offset to x16 if offset != 0
2841 //
2842 // add offset to x16:
2843 // - abs(offset) fits 24 bits:
2844 // add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions)
2845 // - abs(offset) does not fit 24 bits:
2846 // - offset < 0:
2847 // movn+movk sequence filling x17 register with the offset (up to 4
2848 // instructions)
2849 // add x16, x16, x17
2850 // - offset > 0:
2851 // movz+movk sequence filling x17 register with the offset (up to 4
2852 // instructions)
2853 // add x16, x16, x17
2854 //
2855 // signing:
2856 // - 0 discriminator:
2857 // paciza x16
2858 // - Non-0 discriminator, no address discriminator:
2859 // mov x17, #Disc
2860 // pacia x16, x17
2861 // - address discriminator (with potentially folded immediate discriminator):
2862 // pacia x16, xAddrDisc
2863
2864 MachineOperand GAMOHi(GAOp), GAMOLo(GAOp);
2865 MCOperand GAMCHi, GAMCLo;
2866
2867 GAMOHi.setTargetFlags(AArch64II::MO_PAGE);
2868 GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2869 if (IsGOTLoad) {
2870 GAMOHi.addTargetFlag(AArch64II::MO_GOT);
2871 GAMOLo.addTargetFlag(AArch64II::MO_GOT);
2872 }
2873
2874 MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
2875 MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
2876
2877 EmitToStreamer(
2878 MCInstBuilder(AArch64::ADRP)
2879 .addReg(IsGOTLoad && IsELFSignedGOT ? AArch64::X17 : AArch64::X16)
2880 .addOperand(GAMCHi));
2881
2882 if (IsGOTLoad) {
2883 if (IsELFSignedGOT) {
2884 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
2885 .addReg(AArch64::X17)
2886 .addReg(AArch64::X17)
2887 .addOperand(GAMCLo)
2888 .addImm(0));
2889
2890 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
2891 .addReg(AArch64::X16)
2892 .addReg(AArch64::X17)
2893 .addImm(0));
2894
2895 assert(GAOp.isGlobal());
2896 assert(GAOp.getGlobal()->getValueType() != nullptr);
2897
2898 bool IsFunctionTy = GAOp.getGlobal()->getValueType()->isFunctionTy();
2899 auto AuthKey = IsFunctionTy ? AArch64PACKey::IA : AArch64PACKey::DA;
2900 emitAUT(AuthKey, AArch64::X16, AArch64::X17);
2901
2902 if (!STI->hasFPAC())
2903 emitPtrauthCheckAuthenticatedValue(AArch64::X16, AArch64::X17, AuthKey,
2904 AArch64PAuth::AuthCheckMethod::XPAC);
2905 } else {
2906 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
2907 .addReg(AArch64::X16)
2908 .addReg(AArch64::X16)
2909 .addOperand(GAMCLo));
2910 }
2911 } else {
2912 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
2913 .addReg(AArch64::X16)
2914 .addReg(AArch64::X16)
2915 .addOperand(GAMCLo)
2916 .addImm(0));
2917 }
2918
2919 emitAddImm(AArch64::X16, Offset, AArch64::X17);
2920 Register DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, AArch64::X17);
2921
2922 emitPAC(Key, AArch64::X16, DiscReg);
2923}
2924
2925void AArch64AsmPrinter::LowerLOADgotAUTH(const MachineInstr &MI) {
2926 Register DstReg = MI.getOperand(0).getReg();
2927 Register AuthResultReg = STI->hasFPAC() ? DstReg : AArch64::X16;
2928 const MachineOperand &GAMO = MI.getOperand(1);
2929 assert(GAMO.getOffset() == 0);
2930
2931 if (MI.getMF()->getTarget().getCodeModel() == CodeModel::Tiny) {
2932 MCOperand GAMC;
2933 MCInstLowering.lowerOperand(GAMO, GAMC);
2934 EmitToStreamer(
2935 MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addOperand(GAMC));
2936 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
2937 .addReg(AuthResultReg)
2938 .addReg(AArch64::X17)
2939 .addImm(0));
2940 } else {
2941 MachineOperand GAHiOp(GAMO);
2942 MachineOperand GALoOp(GAMO);
2943 GAHiOp.addTargetFlag(AArch64II::MO_PAGE);
2944 GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2945
2946 MCOperand GAMCHi, GAMCLo;
2947 MCInstLowering.lowerOperand(GAHiOp, GAMCHi);
2948 MCInstLowering.lowerOperand(GALoOp, GAMCLo);
2949
2950 EmitToStreamer(
2951 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(GAMCHi));
2952
2953 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
2954 .addReg(AArch64::X17)
2955 .addReg(AArch64::X17)
2956 .addOperand(GAMCLo)
2957 .addImm(0));
2958
2959 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
2960 .addReg(AuthResultReg)
2961 .addReg(AArch64::X17)
2962 .addImm(0));
2963 }
2964
2965 assert(GAMO.isGlobal());
2966 MCSymbol *UndefWeakSym;
2967 if (GAMO.getGlobal()->hasExternalWeakLinkage()) {
2968 UndefWeakSym = createTempSymbol("undef_weak");
2969 EmitToStreamer(
2970 MCInstBuilder(AArch64::CBZX)
2971 .addReg(AuthResultReg)
2972 .addExpr(MCSymbolRefExpr::create(UndefWeakSym, OutContext)));
2973 }
2974
2975 assert(GAMO.getGlobal()->getValueType() != nullptr);
2976
2977 bool IsFunctionTy = GAMO.getGlobal()->getValueType()->isFunctionTy();
2978 auto AuthKey = IsFunctionTy ? AArch64PACKey::IA : AArch64PACKey::DA;
2979 emitAUT(AuthKey, AuthResultReg, AArch64::X17);
2980
2981 if (GAMO.getGlobal()->hasExternalWeakLinkage())
2982 OutStreamer->emitLabel(UndefWeakSym);
2983
2984 if (!STI->hasFPAC()) {
2985 emitPtrauthCheckAuthenticatedValue(AuthResultReg, AArch64::X17, AuthKey,
2986 AArch64PAuth::AuthCheckMethod::XPAC);
2987
2988 emitMovXReg(DstReg, AuthResultReg);
2989 }
2990}
2991
2992const MCExpr *
2993AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) {
2994 const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant(BA);
2995 const Function &Fn = *BA.getFunction();
2996
2997 if (std::optional<uint16_t> BADisc =
2998 STI->getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn))
2999 return AArch64AuthMCExpr::create(BAE, *BADisc, AArch64PACKey::IA,
3000 /*HasAddressDiversity=*/false, OutContext);
3001
3002 return BAE;
3003}
3004
3005void AArch64AsmPrinter::emitCBPseudoExpansion(const MachineInstr *MI) {
3006 bool IsImm = false;
3007 unsigned Width = 0;
3008
3009 switch (MI->getOpcode()) {
3010 default:
3011 llvm_unreachable("This is not a CB pseudo instruction");
3012 case AArch64::CBBAssertExt:
3013 IsImm = false;
3014 Width = 8;
3015 break;
3016 case AArch64::CBHAssertExt:
3017 IsImm = false;
3018 Width = 16;
3019 break;
3020 case AArch64::CBWPrr:
3021 Width = 32;
3022 break;
3023 case AArch64::CBXPrr:
3024 Width = 64;
3025 break;
3026 case AArch64::CBWPri:
3027 IsImm = true;
3028 Width = 32;
3029 break;
3030 case AArch64::CBXPri:
3031 IsImm = true;
3032 Width = 64;
3033 break;
3034 }
3035
3037 static_cast<AArch64CC::CondCode>(MI->getOperand(0).getImm());
3038 bool NeedsRegSwap = false;
3039 bool NeedsImmDec = false;
3040 bool NeedsImmInc = false;
3041
3042#define GET_CB_OPC(IsImm, Width, ImmCond, RegCond) \
3043 (IsImm \
3044 ? (Width == 32 ? AArch64::CB##ImmCond##Wri : AArch64::CB##ImmCond##Xri) \
3045 : (Width == 8 \
3046 ? AArch64::CBB##RegCond##Wrr \
3047 : (Width == 16 ? AArch64::CBH##RegCond##Wrr \
3048 : (Width == 32 ? AArch64::CB##RegCond##Wrr \
3049 : AArch64::CB##RegCond##Xrr))))
3050 unsigned MCOpC;
3051
3052 // Decide if we need to either swap register operands or increment/decrement
3053 // immediate operands
3054 switch (CC) {
3055 default:
3056 llvm_unreachable("Invalid CB condition code");
3057 case AArch64CC::EQ:
3058 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ EQ, /* Reg-Reg */ EQ);
3059 break;
3060 case AArch64CC::NE:
3061 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ NE, /* Reg-Reg */ NE);
3062 break;
3063 case AArch64CC::HS:
3064 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ HI, /* Reg-Reg */ HS);
3065 NeedsImmDec = IsImm;
3066 break;
3067 case AArch64CC::LO:
3068 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LO, /* Reg-Reg */ HI);
3069 NeedsRegSwap = !IsImm;
3070 break;
3071 case AArch64CC::HI:
3072 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ HI, /* Reg-Reg */ HI);
3073 break;
3074 case AArch64CC::LS:
3075 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LO, /* Reg-Reg */ HS);
3076 NeedsRegSwap = !IsImm;
3077 NeedsImmInc = IsImm;
3078 break;
3079 case AArch64CC::GE:
3080 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ GT, /* Reg-Reg */ GE);
3081 NeedsImmDec = IsImm;
3082 break;
3083 case AArch64CC::LT:
3084 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LT, /* Reg-Reg */ GT);
3085 NeedsRegSwap = !IsImm;
3086 break;
3087 case AArch64CC::GT:
3088 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ GT, /* Reg-Reg */ GT);
3089 break;
3090 case AArch64CC::LE:
3091 MCOpC = GET_CB_OPC(IsImm, Width, /* Reg-Imm */ LT, /* Reg-Reg */ GE);
3092 NeedsRegSwap = !IsImm;
3093 NeedsImmInc = IsImm;
3094 break;
3095 }
3096#undef GET_CB_OPC
3097
3098 MCInst Inst;
3099 Inst.setOpcode(MCOpC);
3100
3101 MCOperand Lhs, Rhs, Trgt;
3102 lowerOperand(MI->getOperand(1), Lhs);
3103 lowerOperand(MI->getOperand(2), Rhs);
3104 lowerOperand(MI->getOperand(3), Trgt);
3105
3106 // Now swap, increment or decrement
3107 if (NeedsRegSwap) {
3108 assert(Lhs.isReg() && "Expected register operand for CB");
3109 assert(Rhs.isReg() && "Expected register operand for CB");
3110 Inst.addOperand(Rhs);
3111 Inst.addOperand(Lhs);
3112 } else if (NeedsImmDec) {
3113 Rhs.setImm(Rhs.getImm() - 1);
3114 Inst.addOperand(Lhs);
3115 Inst.addOperand(Rhs);
3116 } else if (NeedsImmInc) {
3117 Rhs.setImm(Rhs.getImm() + 1);
3118 Inst.addOperand(Lhs);
3119 Inst.addOperand(Rhs);
3120 } else {
3121 Inst.addOperand(Lhs);
3122 Inst.addOperand(Rhs);
3123 }
3124
3125 assert((!IsImm || (Rhs.getImm() >= 0 && Rhs.getImm() < 64)) &&
3126 "CB immediate operand out-of-bounds");
3127
3128 Inst.addOperand(Trgt);
3129 EmitToStreamer(*OutStreamer, Inst);
3130}
3131
3132// Simple pseudo-instructions have their lowering (with expansion to real
3133// instructions) auto-generated.
3134#include "AArch64GenMCPseudoLowering.inc"
3135
3136void AArch64AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
3137 S.emitInstruction(Inst, *STI);
3138#ifndef NDEBUG
3139 ++InstsEmitted;
3140#endif
3141}
3142
3143void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
3144 AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
3145
3146#ifndef NDEBUG
3147 InstsEmitted = 0;
3148 llvm::scope_exit CheckMISize([&]() {
3149 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
3150 });
3151#endif
3152
3153 // Do any auto-generated pseudo lowerings.
3154 if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {
3155 EmitToStreamer(*OutStreamer, OutInst);
3156 return;
3157 }
3158
3159 if (MI->getOpcode() == AArch64::ADRP) {
3160 for (auto &Opd : MI->operands()) {
3161 if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) ==
3162 "swift_async_extendedFramePointerFlags") {
3163 ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true;
3164 }
3165 }
3166 }
3167
3168 if (AArch64FI->getLOHRelated().count(MI)) {
3169 // Generate a label for LOH related instruction
3170 MCSymbol *LOHLabel = createTempSymbol("loh");
3171 // Associate the instruction with the label
3172 LOHInstToLabel[MI] = LOHLabel;
3173 OutStreamer->emitLabel(LOHLabel);
3174 }
3175
3176 AArch64TargetStreamer *TS =
3177 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
3178 // Do any manual lowerings.
3179 switch (MI->getOpcode()) {
3180 default:
3182 "Unhandled tail call instruction");
3183 break;
3184 case AArch64::HINT: {
3185 // CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for
3186 // -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be
3187 // non-empty. If MI is the initial BTI, place the
3188 // __patchable_function_entries label after BTI.
3189 if (CurrentPatchableFunctionEntrySym &&
3190 CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
3191 MI == &MF->front().front()) {
3192 int64_t Imm = MI->getOperand(0).getImm();
3193 if ((Imm & 32) && (Imm & 6)) {
3194 MCInst Inst;
3195 MCInstLowering.Lower(MI, Inst);
3196 EmitToStreamer(*OutStreamer, Inst);
3197 CurrentPatchableFunctionEntrySym = createTempSymbol("patch");
3198 OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym);
3199 return;
3200 }
3201 }
3202 break;
3203 }
3204 case AArch64::MOVMCSym: {
3205 Register DestReg = MI->getOperand(0).getReg();
3206 const MachineOperand &MO_Sym = MI->getOperand(1);
3207 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
3208 MCOperand Hi_MCSym, Lo_MCSym;
3209
3210 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
3211 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
3212
3213 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
3214 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
3215
3216 MCInst MovZ;
3217 MovZ.setOpcode(AArch64::MOVZXi);
3218 MovZ.addOperand(MCOperand::createReg(DestReg));
3219 MovZ.addOperand(Hi_MCSym);
3221 EmitToStreamer(*OutStreamer, MovZ);
3222
3223 MCInst MovK;
3224 MovK.setOpcode(AArch64::MOVKXi);
3225 MovK.addOperand(MCOperand::createReg(DestReg));
3226 MovK.addOperand(MCOperand::createReg(DestReg));
3227 MovK.addOperand(Lo_MCSym);
3229 EmitToStreamer(*OutStreamer, MovK);
3230 return;
3231 }
3232 case AArch64::MOVIv2d_ns:
3233 // It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0".
3234 // as movi is more efficient across all cores. Newer cores can eliminate
3235 // fmovs early and there is no difference with movi, but this not true for
3236 // all implementations.
3237 //
3238 // The floating-point version doesn't quite work in rare cases on older
3239 // CPUs, so on those targets we lower this instruction to movi.16b instead.
3240 if (STI->hasZeroCycleZeroingFPWorkaround() &&
3241 MI->getOperand(1).getImm() == 0) {
3242 MCInst TmpInst;
3243 TmpInst.setOpcode(AArch64::MOVIv16b_ns);
3244 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
3245 TmpInst.addOperand(MCOperand::createImm(0));
3246 EmitToStreamer(*OutStreamer, TmpInst);
3247 return;
3248 }
3249 break;
3250
3251 case AArch64::DBG_VALUE:
3252 case AArch64::DBG_VALUE_LIST:
3253 if (isVerbose() && OutStreamer->hasRawTextSupport()) {
3254 SmallString<128> TmpStr;
3255 raw_svector_ostream OS(TmpStr);
3256 PrintDebugValueComment(MI, OS);
3257 OutStreamer->emitRawText(StringRef(OS.str()));
3258 }
3259 return;
3260
3261 case AArch64::EMITBKEY: {
3262 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
3263 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
3264 ExceptionHandlingType != ExceptionHandling::ARM)
3265 return;
3266
3267 if (getFunctionCFISectionType(*MF) == CFISection::None)
3268 return;
3269
3270 OutStreamer->emitCFIBKeyFrame();
3271 return;
3272 }
3273
3274 case AArch64::EMITMTETAGGED: {
3275 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
3276 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
3277 ExceptionHandlingType != ExceptionHandling::ARM)
3278 return;
3279
3280 if (getFunctionCFISectionType(*MF) != CFISection::None)
3281 OutStreamer->emitCFIMTETaggedFrame();
3282 return;
3283 }
3284
3285 case AArch64::AUTx16x17: {
3286 const Register Pointer = AArch64::X16;
3287 const Register Scratch = AArch64::X17;
3288
3289 PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(),
3290 MI->getOperand(1).getImm(), MI->getOperand(2));
3291
3292 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, std::nullopt,
3293 std::nullopt, MI->getDeactivationSymbol());
3294 return;
3295 }
3296
3297 case AArch64::AUTxMxN: {
3298 const Register Pointer = MI->getOperand(0).getReg();
3299 const Register Scratch = MI->getOperand(1).getReg();
3300
3301 PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(3).getImm(),
3302 MI->getOperand(4).getImm(), MI->getOperand(5));
3303
3304 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, std::nullopt,
3305 std::nullopt, MI->getDeactivationSymbol());
3306 return;
3307 }
3308
3309 case AArch64::AUTPAC: {
3310 const Register Pointer = AArch64::X16;
3311 const Register Scratch = AArch64::X17;
3312
3313 PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(),
3314 MI->getOperand(1).getImm(), MI->getOperand(2));
3315
3316 PtrAuthSchema SignSchema((AArch64PACKey::ID)MI->getOperand(3).getImm(),
3317 MI->getOperand(4).getImm(), MI->getOperand(5));
3318
3319 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, SignSchema,
3320 std::nullopt, MI->getDeactivationSymbol());
3321 return;
3322 }
3323
3324 case AArch64::AUTRELLOADPAC: {
3325 const Register Pointer = AArch64::X16;
3326 const Register Scratch = AArch64::X17;
3327
3328 PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(),
3329 MI->getOperand(1).getImm(), MI->getOperand(2));
3330
3331 PtrAuthSchema SignSchema((AArch64PACKey::ID)MI->getOperand(3).getImm(),
3332 MI->getOperand(4).getImm(), MI->getOperand(5));
3333
3334 emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, SignSchema,
3335 MI->getOperand(6).getImm(),
3336 MI->getDeactivationSymbol());
3337
3338 return;
3339 }
3340
3341 case AArch64::PAC:
3342 emitPtrauthSign(MI);
3343 return;
3344
3345 case AArch64::LOADauthptrstatic:
3346 LowerLOADauthptrstatic(*MI);
3347 return;
3348
3349 case AArch64::LOADgotPAC:
3350 case AArch64::MOVaddrPAC:
3351 LowerMOVaddrPAC(*MI);
3352 return;
3353
3354 case AArch64::LOADgotAUTH:
3355 LowerLOADgotAUTH(*MI);
3356 return;
3357
3358 case AArch64::BRA:
3359 case AArch64::BLRA:
3360 emitPtrauthBranch(MI);
3361 return;
3362
3363 // Tail calls use pseudo instructions so they have the proper code-gen
3364 // attributes (isCall, isReturn, etc.). We lower them to the real
3365 // instruction here.
3366 case AArch64::AUTH_TCRETURN:
3367 case AArch64::AUTH_TCRETURN_BTI: {
3368 Register Callee = MI->getOperand(0).getReg();
3369 const auto Key = (AArch64PACKey::ID)MI->getOperand(2).getImm();
3370 const uint64_t Disc = MI->getOperand(3).getImm();
3371
3372 Register AddrDisc = MI->getOperand(4).getReg();
3373
3374 Register ScratchReg = Callee == AArch64::X16 ? AArch64::X17 : AArch64::X16;
3375
3376 emitPtrauthTailCallHardening(MI);
3377
3378 // See the comments in emitPtrauthBranch.
3379 if (Callee == AddrDisc)
3380 report_fatal_error("Call target is signed with its own value");
3381
3382 // After isX16X17Safer predicate was introduced, emitPtrauthDiscriminator is
3383 // no longer restricted to only reusing AddrDisc when it is X16 or X17
3384 // (which are implicit-def'ed by AUTH_TCRETURN pseudos), thus impose this
3385 // restriction manually not to clobber an unexpected register.
3386 bool AddrDiscIsImplicitDef =
3387 AddrDisc == AArch64::X16 || AddrDisc == AArch64::X17;
3388 Register DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, ScratchReg,
3389 AddrDiscIsImplicitDef);
3390 emitBLRA(/*IsCall*/ false, Key, Callee, DiscReg);
3391 return;
3392 }
3393
3394 case AArch64::TCRETURNri:
3395 case AArch64::TCRETURNrix16x17:
3396 case AArch64::TCRETURNrix17:
3397 case AArch64::TCRETURNrinotx16:
3398 case AArch64::TCRETURNriALL: {
3399 emitPtrauthTailCallHardening(MI);
3400
3401 recordIfImportCall(MI);
3402 MCInst TmpInst;
3403 TmpInst.setOpcode(AArch64::BR);
3404 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
3405 EmitToStreamer(*OutStreamer, TmpInst);
3406 return;
3407 }
3408 case AArch64::TCRETURNdi: {
3409 emitPtrauthTailCallHardening(MI);
3410
3411 MCOperand Dest;
3412 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
3413 recordIfImportCall(MI);
3414 MCInst TmpInst;
3415 TmpInst.setOpcode(AArch64::B);
3416 TmpInst.addOperand(Dest);
3417 EmitToStreamer(*OutStreamer, TmpInst);
3418 return;
3419 }
3420 case AArch64::SpeculationBarrierISBDSBEndBB: {
3421 // Print DSB SYS + ISB
3422 MCInst TmpInstDSB;
3423 TmpInstDSB.setOpcode(AArch64::DSB);
3424 TmpInstDSB.addOperand(MCOperand::createImm(0xf));
3425 EmitToStreamer(*OutStreamer, TmpInstDSB);
3426 MCInst TmpInstISB;
3427 TmpInstISB.setOpcode(AArch64::ISB);
3428 TmpInstISB.addOperand(MCOperand::createImm(0xf));
3429 EmitToStreamer(*OutStreamer, TmpInstISB);
3430 return;
3431 }
3432 case AArch64::SpeculationBarrierSBEndBB: {
3433 // Print SB
3434 MCInst TmpInstSB;
3435 TmpInstSB.setOpcode(AArch64::SB);
3436 EmitToStreamer(*OutStreamer, TmpInstSB);
3437 return;
3438 }
3439 case AArch64::TLSDESC_AUTH_CALLSEQ: {
3440 /// lower this to:
3441 /// adrp x0, :tlsdesc_auth:var
3442 /// ldr x16, [x0, #:tlsdesc_auth_lo12:var]
3443 /// add x0, x0, #:tlsdesc_auth_lo12:var
3444 /// blraa x16, x0
3445 /// (TPIDR_EL0 offset now in x0)
3446 const MachineOperand &MO_Sym = MI->getOperand(0);
3447 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
3448 MCOperand SymTLSDescLo12, SymTLSDesc;
3449 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
3450 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
3451 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
3452 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
3453
3454 MCInst Adrp;
3455 Adrp.setOpcode(AArch64::ADRP);
3456 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
3457 Adrp.addOperand(SymTLSDesc);
3458 EmitToStreamer(*OutStreamer, Adrp);
3459
3460 MCInst Ldr;
3461 Ldr.setOpcode(AArch64::LDRXui);
3462 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
3463 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
3464 Ldr.addOperand(SymTLSDescLo12);
3466 EmitToStreamer(*OutStreamer, Ldr);
3467
3468 MCInst Add;
3469 Add.setOpcode(AArch64::ADDXri);
3470 Add.addOperand(MCOperand::createReg(AArch64::X0));
3471 Add.addOperand(MCOperand::createReg(AArch64::X0));
3472 Add.addOperand(SymTLSDescLo12);
3474 EmitToStreamer(*OutStreamer, Add);
3475
3476 // Authenticated TLSDESC accesses are not relaxed.
3477 // Thus, do not emit .tlsdesccall for AUTH TLSDESC.
3478
3479 MCInst Blraa;
3480 Blraa.setOpcode(AArch64::BLRAA);
3481 Blraa.addOperand(MCOperand::createReg(AArch64::X16));
3482 Blraa.addOperand(MCOperand::createReg(AArch64::X0));
3483 EmitToStreamer(*OutStreamer, Blraa);
3484
3485 return;
3486 }
3487 case AArch64::TLSDESC_CALLSEQ: {
3488 /// lower this to:
3489 /// adrp x0, :tlsdesc:var
3490 /// ldr x1, [x0, #:tlsdesc_lo12:var]
3491 /// add x0, x0, #:tlsdesc_lo12:var
3492 /// .tlsdesccall var
3493 /// blr x1
3494 /// (TPIDR_EL0 offset now in x0)
3495 const MachineOperand &MO_Sym = MI->getOperand(0);
3496 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
3497 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
3498 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
3499 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
3500 MCInstLowering.lowerOperand(MO_Sym, Sym);
3501 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
3502 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
3503
3504 MCInst Adrp;
3505 Adrp.setOpcode(AArch64::ADRP);
3506 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
3507 Adrp.addOperand(SymTLSDesc);
3508 EmitToStreamer(*OutStreamer, Adrp);
3509
3510 MCInst Ldr;
3511 if (STI->isTargetILP32()) {
3512 Ldr.setOpcode(AArch64::LDRWui);
3513 Ldr.addOperand(MCOperand::createReg(AArch64::W1));
3514 } else {
3515 Ldr.setOpcode(AArch64::LDRXui);
3516 Ldr.addOperand(MCOperand::createReg(AArch64::X1));
3517 }
3518 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
3519 Ldr.addOperand(SymTLSDescLo12);
3521 EmitToStreamer(*OutStreamer, Ldr);
3522
3523 MCInst Add;
3524 if (STI->isTargetILP32()) {
3525 Add.setOpcode(AArch64::ADDWri);
3526 Add.addOperand(MCOperand::createReg(AArch64::W0));
3527 Add.addOperand(MCOperand::createReg(AArch64::W0));
3528 } else {
3529 Add.setOpcode(AArch64::ADDXri);
3530 Add.addOperand(MCOperand::createReg(AArch64::X0));
3531 Add.addOperand(MCOperand::createReg(AArch64::X0));
3532 }
3533 Add.addOperand(SymTLSDescLo12);
3535 EmitToStreamer(*OutStreamer, Add);
3536
3537 // Emit a relocation-annotation. This expands to no code, but requests
3538 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
3539 MCInst TLSDescCall;
3540 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
3541 TLSDescCall.addOperand(Sym);
3542 EmitToStreamer(*OutStreamer, TLSDescCall);
3543#ifndef NDEBUG
3544 --InstsEmitted; // no code emitted
3545#endif
3546
3547 MCInst Blr;
3548 Blr.setOpcode(AArch64::BLR);
3549 Blr.addOperand(MCOperand::createReg(AArch64::X1));
3550 EmitToStreamer(*OutStreamer, Blr);
3551
3552 return;
3553 }
3554
3555 case AArch64::JumpTableDest32:
3556 case AArch64::JumpTableDest16:
3557 case AArch64::JumpTableDest8:
3558 LowerJumpTableDest(*OutStreamer, *MI);
3559 return;
3560
3561 case AArch64::BR_JumpTable:
3562 LowerHardenedBRJumpTable(*MI);
3563 return;
3564
3565 case AArch64::FMOVH0:
3566 case AArch64::FMOVS0:
3567 case AArch64::FMOVD0:
3568 emitFMov0(*MI);
3569 return;
3570
3571 case AArch64::MOPSMemoryCopyPseudo:
3572 case AArch64::MOPSMemoryMovePseudo:
3573 case AArch64::MOPSMemorySetPseudo:
3574 case AArch64::MOPSMemorySetTaggingPseudo:
3575 LowerMOPS(*OutStreamer, *MI);
3576 return;
3577
3578 case TargetOpcode::STACKMAP:
3579 return LowerSTACKMAP(*OutStreamer, SM, *MI);
3580
3581 case TargetOpcode::PATCHPOINT:
3582 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
3583
3584 case TargetOpcode::STATEPOINT:
3585 return LowerSTATEPOINT(*OutStreamer, SM, *MI);
3586
3587 case TargetOpcode::FAULTING_OP:
3588 return LowerFAULTING_OP(*MI);
3589
3590 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
3591 LowerPATCHABLE_FUNCTION_ENTER(*MI);
3592 return;
3593
3594 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
3595 LowerPATCHABLE_FUNCTION_EXIT(*MI);
3596 return;
3597
3598 case TargetOpcode::PATCHABLE_TAIL_CALL:
3599 LowerPATCHABLE_TAIL_CALL(*MI);
3600 return;
3601 case TargetOpcode::PATCHABLE_EVENT_CALL:
3602 return LowerPATCHABLE_EVENT_CALL(*MI, false);
3603 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
3604 return LowerPATCHABLE_EVENT_CALL(*MI, true);
3605
3606 case AArch64::KCFI_CHECK:
3607 LowerKCFI_CHECK(*MI);
3608 return;
3609
3610 case AArch64::HWASAN_CHECK_MEMACCESS:
3611 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
3612 case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
3613 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
3614 LowerHWASAN_CHECK_MEMACCESS(*MI);
3615 return;
3616
3617 case AArch64::SEH_StackAlloc:
3618 TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
3619 return;
3620
3621 case AArch64::SEH_SaveFPLR:
3622 TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
3623 return;
3624
3625 case AArch64::SEH_SaveFPLR_X:
3626 assert(MI->getOperand(0).getImm() < 0 &&
3627 "Pre increment SEH opcode must have a negative offset");
3628 TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
3629 return;
3630
3631 case AArch64::SEH_SaveReg:
3632 TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
3633 MI->getOperand(1).getImm());
3634 return;
3635
3636 case AArch64::SEH_SaveReg_X:
3637 assert(MI->getOperand(1).getImm() < 0 &&
3638 "Pre increment SEH opcode must have a negative offset");
3639 TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
3640 -MI->getOperand(1).getImm());
3641 return;
3642
3643 case AArch64::SEH_SaveRegP:
3644 if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 &&
3645 MI->getOperand(0).getImm() <= 28) {
3646 assert((MI->getOperand(0).getImm() - 19) % 2 == 0 &&
3647 "Register paired with LR must be odd");
3648 TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(),
3649 MI->getOperand(2).getImm());
3650 return;
3651 }
3652 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
3653 "Non-consecutive registers not allowed for save_regp");
3654 TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
3655 MI->getOperand(2).getImm());
3656 return;
3657
3658 case AArch64::SEH_SaveRegP_X:
3659 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
3660 "Non-consecutive registers not allowed for save_regp_x");
3661 assert(MI->getOperand(2).getImm() < 0 &&
3662 "Pre increment SEH opcode must have a negative offset");
3663 TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
3664 -MI->getOperand(2).getImm());
3665 return;
3666
3667 case AArch64::SEH_SaveFReg:
3668 TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
3669 MI->getOperand(1).getImm());
3670 return;
3671
3672 case AArch64::SEH_SaveFReg_X:
3673 assert(MI->getOperand(1).getImm() < 0 &&
3674 "Pre increment SEH opcode must have a negative offset");
3675 TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
3676 -MI->getOperand(1).getImm());
3677 return;
3678
3679 case AArch64::SEH_SaveFRegP:
3680 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
3681 "Non-consecutive registers not allowed for save_regp");
3682 TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
3683 MI->getOperand(2).getImm());
3684 return;
3685
3686 case AArch64::SEH_SaveFRegP_X:
3687 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
3688 "Non-consecutive registers not allowed for save_regp_x");
3689 assert(MI->getOperand(2).getImm() < 0 &&
3690 "Pre increment SEH opcode must have a negative offset");
3691 TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
3692 -MI->getOperand(2).getImm());
3693 return;
3694
3695 case AArch64::SEH_SetFP:
3697 return;
3698
3699 case AArch64::SEH_AddFP:
3700 TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm());
3701 return;
3702
3703 case AArch64::SEH_Nop:
3704 TS->emitARM64WinCFINop();
3705 return;
3706
3707 case AArch64::SEH_PrologEnd:
3709 return;
3710
3711 case AArch64::SEH_EpilogStart:
3713 return;
3714
3715 case AArch64::SEH_EpilogEnd:
3717 return;
3718
3719 case AArch64::SEH_PACSignLR:
3721 return;
3722
3723 case AArch64::SEH_SaveAnyRegI:
3724 assert(MI->getOperand(1).getImm() <= 1008 &&
3725 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3726 TS->emitARM64WinCFISaveAnyRegI(MI->getOperand(0).getImm(),
3727 MI->getOperand(1).getImm());
3728 return;
3729
3730 case AArch64::SEH_SaveAnyRegIP:
3731 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
3732 "Non-consecutive registers not allowed for save_any_reg");
3733 assert(MI->getOperand(2).getImm() <= 1008 &&
3734 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3735 TS->emitARM64WinCFISaveAnyRegIP(MI->getOperand(0).getImm(),
3736 MI->getOperand(2).getImm());
3737 return;
3738
3739 case AArch64::SEH_SaveAnyRegQP:
3740 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
3741 "Non-consecutive registers not allowed for save_any_reg");
3742 assert(MI->getOperand(2).getImm() >= 0 &&
3743 "SaveAnyRegQP SEH opcode offset must be non-negative");
3744 assert(MI->getOperand(2).getImm() <= 1008 &&
3745 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3746 TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(),
3747 MI->getOperand(2).getImm());
3748 return;
3749
3750 case AArch64::SEH_SaveAnyRegQPX:
3751 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
3752 "Non-consecutive registers not allowed for save_any_reg");
3753 assert(MI->getOperand(2).getImm() < 0 &&
3754 "SaveAnyRegQPX SEH opcode offset must be negative");
3755 assert(MI->getOperand(2).getImm() >= -1008 &&
3756 "SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
3757 TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(),
3758 -MI->getOperand(2).getImm());
3759 return;
3760
3761 case AArch64::SEH_AllocZ:
3762 assert(MI->getOperand(0).getImm() >= 0 &&
3763 "AllocZ SEH opcode offset must be non-negative");
3764 assert(MI->getOperand(0).getImm() <= 255 &&
3765 "AllocZ SEH opcode offset must fit into 8 bits");
3766 TS->emitARM64WinCFIAllocZ(MI->getOperand(0).getImm());
3767 return;
3768
3769 case AArch64::SEH_SaveZReg:
3770 assert(MI->getOperand(1).getImm() >= 0 &&
3771 "SaveZReg SEH opcode offset must be non-negative");
3772 assert(MI->getOperand(1).getImm() <= 255 &&
3773 "SaveZReg SEH opcode offset must fit into 8 bits");
3774 TS->emitARM64WinCFISaveZReg(MI->getOperand(0).getImm(),
3775 MI->getOperand(1).getImm());
3776 return;
3777
3778 case AArch64::SEH_SavePReg:
3779 assert(MI->getOperand(1).getImm() >= 0 &&
3780 "SavePReg SEH opcode offset must be non-negative");
3781 assert(MI->getOperand(1).getImm() <= 255 &&
3782 "SavePReg SEH opcode offset must fit into 8 bits");
3783 TS->emitARM64WinCFISavePReg(MI->getOperand(0).getImm(),
3784 MI->getOperand(1).getImm());
3785 return;
3786
3787 case AArch64::BLR:
3788 case AArch64::BR: {
3789 recordIfImportCall(MI);
3790 MCInst TmpInst;
3791 MCInstLowering.Lower(MI, TmpInst);
3792 EmitToStreamer(*OutStreamer, TmpInst);
3793 return;
3794 }
3795 case AArch64::CBWPri:
3796 case AArch64::CBXPri:
3797 case AArch64::CBBAssertExt:
3798 case AArch64::CBHAssertExt:
3799 case AArch64::CBWPrr:
3800 case AArch64::CBXPrr:
3801 emitCBPseudoExpansion(MI);
3802 return;
3803 }
3804
3805 if (emitDeactivationSymbolRelocation(MI->getDeactivationSymbol()))
3806 return;
3807
3808 // Finally, do the automated lowerings for everything else.
3809 MCInst TmpInst;
3810 MCInstLowering.Lower(MI, TmpInst);
3811 EmitToStreamer(*OutStreamer, TmpInst);
3812}
3813
3814void AArch64AsmPrinter::recordIfImportCall(
3815 const llvm::MachineInstr *BranchInst) {
3816 if (!EnableImportCallOptimization)
3817 return;
3818
3819 auto [GV, OpFlags] = BranchInst->getMF()->tryGetCalledGlobal(BranchInst);
3820 if (GV && GV->hasDLLImportStorageClass()) {
3821 auto *CallSiteSymbol = MMI->getContext().createNamedTempSymbol("impcall");
3822 OutStreamer->emitLabel(CallSiteSymbol);
3823
3824 auto *CalledSymbol = MCInstLowering.GetGlobalValueSymbol(GV, OpFlags);
3825 SectionToImportedFunctionCalls[OutStreamer->getCurrentSectionOnly()]
3826 .push_back({CallSiteSymbol, CalledSymbol});
3827 }
3828}
3829
3830void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
3831 MCSymbol *LazyPointer) {
3832 // _ifunc:
3833 // adrp x16, lazy_pointer@GOTPAGE
3834 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
3835 // ldr x16, [x16]
3836 // br x16
3837
3838 {
3839 MCInst Adrp;
3840 Adrp.setOpcode(AArch64::ADRP);
3841 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
3842 MCOperand SymPage;
3843 MCInstLowering.lowerOperand(
3846 SymPage);
3847 Adrp.addOperand(SymPage);
3848 EmitToStreamer(Adrp);
3849 }
3850
3851 {
3852 MCInst Ldr;
3853 Ldr.setOpcode(AArch64::LDRXui);
3854 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
3855 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
3856 MCOperand SymPageOff;
3857 MCInstLowering.lowerOperand(
3860 SymPageOff);
3861 Ldr.addOperand(SymPageOff);
3863 EmitToStreamer(Ldr);
3864 }
3865
3866 EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
3867 .addReg(AArch64::X16)
3868 .addReg(AArch64::X16)
3869 .addImm(0));
3870
3871 EmitToStreamer(MCInstBuilder(TM.getTargetTriple().isArm64e() ? AArch64::BRAAZ
3872 : AArch64::BR)
3873 .addReg(AArch64::X16));
3874}
3875
3876void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
3877 const GlobalIFunc &GI,
3878 MCSymbol *LazyPointer) {
3879 // These stub helpers are only ever called once, so here we're optimizing for
3880 // minimum size by using the pre-indexed store variants, which saves a few
3881 // bytes of instructions to bump & restore sp.
3882
3883 // _ifunc.stub_helper:
3884 // stp fp, lr, [sp, #-16]!
3885 // mov fp, sp
3886 // stp x1, x0, [sp, #-16]!
3887 // stp x3, x2, [sp, #-16]!
3888 // stp x5, x4, [sp, #-16]!
3889 // stp x7, x6, [sp, #-16]!
3890 // stp d1, d0, [sp, #-16]!
3891 // stp d3, d2, [sp, #-16]!
3892 // stp d5, d4, [sp, #-16]!
3893 // stp d7, d6, [sp, #-16]!
3894 // bl _resolver
3895 // adrp x16, lazy_pointer@GOTPAGE
3896 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
3897 // str x0, [x16]
3898 // mov x16, x0
3899 // ldp d7, d6, [sp], #16
3900 // ldp d5, d4, [sp], #16
3901 // ldp d3, d2, [sp], #16
3902 // ldp d1, d0, [sp], #16
3903 // ldp x7, x6, [sp], #16
3904 // ldp x5, x4, [sp], #16
3905 // ldp x3, x2, [sp], #16
3906 // ldp x1, x0, [sp], #16
3907 // ldp fp, lr, [sp], #16
3908 // br x16
3909
3910 EmitToStreamer(MCInstBuilder(AArch64::STPXpre)
3911 .addReg(AArch64::SP)
3912 .addReg(AArch64::FP)
3913 .addReg(AArch64::LR)
3914 .addReg(AArch64::SP)
3915 .addImm(-2));
3916
3917 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
3918 .addReg(AArch64::FP)
3919 .addReg(AArch64::SP)
3920 .addImm(0)
3921 .addImm(0));
3922
3923 for (int I = 0; I != 4; ++I)
3924 EmitToStreamer(MCInstBuilder(AArch64::STPXpre)
3925 .addReg(AArch64::SP)
3926 .addReg(AArch64::X1 + 2 * I)
3927 .addReg(AArch64::X0 + 2 * I)
3928 .addReg(AArch64::SP)
3929 .addImm(-2));
3930
3931 for (int I = 0; I != 4; ++I)
3932 EmitToStreamer(MCInstBuilder(AArch64::STPDpre)
3933 .addReg(AArch64::SP)
3934 .addReg(AArch64::D1 + 2 * I)
3935 .addReg(AArch64::D0 + 2 * I)
3936 .addReg(AArch64::SP)
3937 .addImm(-2));
3938
3939 EmitToStreamer(
3940 MCInstBuilder(AArch64::BL)
3942
3943 {
3944 MCInst Adrp;
3945 Adrp.setOpcode(AArch64::ADRP);
3946 Adrp.addOperand(MCOperand::createReg(AArch64::X16));
3947 MCOperand SymPage;
3948 MCInstLowering.lowerOperand(
3949 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
3951 SymPage);
3952 Adrp.addOperand(SymPage);
3953 EmitToStreamer(Adrp);
3954 }
3955
3956 {
3957 MCInst Ldr;
3958 Ldr.setOpcode(AArch64::LDRXui);
3959 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
3960 Ldr.addOperand(MCOperand::createReg(AArch64::X16));
3961 MCOperand SymPageOff;
3962 MCInstLowering.lowerOperand(
3963 MachineOperand::CreateES(LazyPointer->getName().data() + 1,
3965 SymPageOff);
3966 Ldr.addOperand(SymPageOff);
3968 EmitToStreamer(Ldr);
3969 }
3970
3971 EmitToStreamer(MCInstBuilder(AArch64::STRXui)
3972 .addReg(AArch64::X0)
3973 .addReg(AArch64::X16)
3974 .addImm(0));
3975
3976 EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
3977 .addReg(AArch64::X16)
3978 .addReg(AArch64::X0)
3979 .addImm(0)
3980 .addImm(0));
3981
3982 for (int I = 3; I != -1; --I)
3983 EmitToStreamer(MCInstBuilder(AArch64::LDPDpost)
3984 .addReg(AArch64::SP)
3985 .addReg(AArch64::D1 + 2 * I)
3986 .addReg(AArch64::D0 + 2 * I)
3987 .addReg(AArch64::SP)
3988 .addImm(2));
3989
3990 for (int I = 3; I != -1; --I)
3991 EmitToStreamer(MCInstBuilder(AArch64::LDPXpost)
3992 .addReg(AArch64::SP)
3993 .addReg(AArch64::X1 + 2 * I)
3994 .addReg(AArch64::X0 + 2 * I)
3995 .addReg(AArch64::SP)
3996 .addImm(2));
3997
3998 EmitToStreamer(MCInstBuilder(AArch64::LDPXpost)
3999 .addReg(AArch64::SP)
4000 .addReg(AArch64::FP)
4001 .addReg(AArch64::LR)
4002 .addReg(AArch64::SP)
4003 .addImm(2));
4004
4005 EmitToStreamer(MCInstBuilder(TM.getTargetTriple().isArm64e() ? AArch64::BRAAZ
4006 : AArch64::BR)
4007 .addReg(AArch64::X16));
4008}
4009
4010const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV,
4011 const Constant *BaseCV,
4012 uint64_t Offset) {
4013 if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
4014 return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0),
4015 OutContext);
4016 }
4017
4018 return AsmPrinter::lowerConstant(CV, BaseCV, Offset);
4019}
4020
4021char AArch64AsmPrinter::ID = 0;
4022
4023INITIALIZE_PASS(AArch64AsmPrinter, "aarch64-asm-printer",
4024 "AArch64 Assembly Printer", false, false)
4025
4026// Force static initialization.
4027extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
4028LLVMInitializeAArch64AsmPrinter() {
4034}
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
@ Unchecked
#define GET_CB_OPC(IsImm, Width, ImmCond, RegCond)
static void emitAuthenticatedPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel, const MCExpr *StubAuthPtrRef)
static bool targetSupportsIRelativeRelocation(const Triple &TT)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define X(NUM, ENUM, NAME)
Definition ELF.h:851
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
#define LLVM_ABI
Definition Compiler.h:213
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
This file defines the DenseMap class.
@ Default
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
print mir2vec MIR2Vec Vocabulary Printer Pass
Definition MIR2Vec.cpp:598
Machine Check Debug Module
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static constexpr unsigned SM(unsigned Version)
#define P(N)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:483
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
This file defines the SmallString class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
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, SMLoc Loc=SMLoc())
const SetOfInstructions & getLOHRelated() const
unsigned getJumpTableEntrySize(int Idx) const
MCSymbol * getJumpTableEntryPCRelSymbol(int Idx) const
static bool shouldSignReturnAddress(SignReturnAddress Condition, bool IsLRSpilled)
std::optional< std::string > getOutliningStyle() const
const MILOHContainer & getLOHContainer() const
void setJumpTableEntryInfo(int Idx, unsigned Size, MCSymbol *PCRelSym)
static const char * getRegisterName(MCRegister Reg, unsigned AltIdx=AArch64::NoRegAltName)
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
AArch64MCInstLower - This class is used to lower an MachineInstr into an MCInst.
MCSymbol * GetGlobalValueSymbol(const GlobalValue *GV, unsigned TargetFlags) const
void Lower(const MachineInstr *MI, MCInst &OutMI) const
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 emitAttributesSubsection(StringRef VendorName, AArch64BuildAttributes::SubsectionOptional IsOptional, AArch64BuildAttributes::SubsectionType ParameterType)
Build attributes implementation.
virtual void emitARM64WinCFISavePReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegI(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 emitARM64WinCFIAllocZ(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)
virtual void emitARM64WinCFISaveZReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveLRPair(unsigned Reg, int Offset)
virtual void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value, std::string String)
virtual void emitARM64WinCFISaveAnyRegIP(unsigned Reg, int Offset)
void setPreservesAll()
Set by analyses that do not transform their input at all.
const T & front() const
front - Get the first element.
Definition ArrayRef.h:145
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:137
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:91
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 const MCExpr * lowerConstant(const Constant *CV, const Constant *BaseCV=nullptr, uint64_t Offset=0)
Lower the specified LLVM Constant to an MCExpr.
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
virtual void emitXXStructor(const DataLayout &DL, const Constant *CV)
Targets can override this to change how global constants that are part of a C++ static/global constru...
Definition AsmPrinter.h:658
virtual void emitFunctionEntryLabel()
EmitFunctionEntryLabel - Emit the label that is the entrypoint for the function.
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.
Function * getFunction() const
Definition Constants.h:1101
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:168
Constant * getPointer() const
The pointer that is signed in this ptrauth signed pointer.
Definition Constants.h:1226
ConstantInt * getKey() const
The Key ID, an i32 constant.
Definition Constants.h:1229
Constant * getDeactivationSymbol() const
Definition Constants.h:1248
bool hasAddressDiscriminator() const
Whether there is any non-null address discriminator.
Definition Constants.h:1244
ConstantInt * getDiscriminator() const
The integer discriminator, an i64 constant, or 0.
Definition Constants.h:1232
void recordFaultingOp(FaultKind FaultTy, const MCSymbol *FaultingLabel, const MCSymbol *HandlerLabel)
Definition FaultMaps.cpp:28
void serializeToFaultMapSection()
Definition FaultMaps.cpp:45
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:272
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:728
const Constant * getAliasee() const
Definition GlobalAlias.h:87
const Constant * getResolver() const
Definition GlobalIFunc.h:73
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this GlobalObject.
bool hasLocalLinkage() const
bool hasExternalWeakLinkage() const
Type * getValueType() const
LLVM_ABI void emitError(const Instruction *I, 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:423
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:343
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:428
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
MCSectionELF * getELFSection(const Twine &Section, unsigned Type, unsigned Flags)
Definition MCContext.h:550
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
LLVM_ABI MCSymbol * createLinkerPrivateSymbol(const Twine &Name)
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
LLVM_ABI bool evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm) const
Try to evaluate the expression to a relocatable value, i.e.
Definition MCExpr.cpp:450
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
MCSection * getDataSection() const
void setImm(int64_t Val)
Definition MCInst.h:89
static MCOperand createExpr(const MCExpr *Val)
Definition MCInst.h:166
int64_t getImm() const
Definition MCInst.h:84
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
bool isReg() const
Definition MCInst.h:65
uint16_t getEncodingValue(MCRegister Reg) const
Returns the encoding for Reg.
static constexpr unsigned NonUniqueID
Definition MCSection.h:574
static const MCSpecifierExpr * create(const MCExpr *Expr, Spec S, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.cpp:743
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual void emitCFIBKeyFrame()
virtual bool popSection()
Restore the current and previous section from the section stack.
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual void emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc={})
Record a relocation described by the .reloc directive.
virtual bool hasRawTextSupport() const
Return true if this asm streamer supports emitting unformatted text to the .s file with EmitRawText.
Definition MCStreamer.h:375
MCContext & getContext() const
Definition MCStreamer.h:323
virtual void AddComment(const Twine &T, bool EOL=true)
Add a textual comment.
Definition MCStreamer.h:394
virtual void emitCFIMTETaggedFrame()
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
MCTargetStreamer * getTargetStreamer()
Definition MCStreamer.h:333
void pushSection()
Save the current and previous section on the section stack.
Definition MCStreamer.h:450
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
MCSection * getCurrentSectionOnly() const
Definition MCStreamer.h:428
void emitRawText(const Twine &String)
If this file is backed by a assembly streamer, this dumps the specified string in the output ....
const FeatureBitset & getFeatureBits() const
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:59
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
const MCSymbol * getAddSym() const
Definition MCValue.h:49
int64_t getConstant() const
Definition MCValue.h:44
MachineInstrBundleIterator< const MachineInstr > const_iterator
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
CalledGlobalInfo tryGetCalledGlobal(const MachineInstr *MI) const
Tries to get the global and target flags for a call site, if the instruction is a call to a global.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MCContext & getContext() const
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...
const MachineBasicBlock & front() const
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
mop_range operands()
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
const std::vector< MachineJumpTableEntry > & getJumpTables() const
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)
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
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.
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:36
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
static SectionKind getMetadata()
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void push_back(const T &Elt)
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:137
virtual MCSection * getSectionForJumpTable(const Function &F, const TargetMachine &TM) const
Primary interface to the complete machine description for the target machine.
MCRegister getRegister(unsigned i) const
Return the specified register in the class.
bool regsOverlap(Register RegA, Register RegB) const
Returns true if the two registers are equal or alias each other.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
bool isFunctionTy() const
True if this is an instance of FunctionType.
Definition Type.h:275
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:258
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:318
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
StringRef getVendorName(unsigned const Vendor)
@ 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.
AuthCheckMethod
Variants of check performed on an authenticated pointer.
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 ==...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ SectionSize
Definition COFF.h:61
SymbolStorageClass
Storage class tells where and what the symbol represents.
Definition COFF.h:218
@ IMAGE_SYM_CLASS_EXTERNAL
External symbol.
Definition COFF.h:224
@ IMAGE_SYM_CLASS_STATIC
Static.
Definition COFF.h:225
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
Definition COFF.h:276
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
Definition COFF.h:280
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ SHF_ALLOC
Definition ELF.h:1249
@ SHF_GROUP
Definition ELF.h:1271
@ SHF_EXECINSTR
Definition ELF.h:1252
@ GNU_PROPERTY_AARCH64_FEATURE_1_BTI
Definition ELF.h:1860
@ GNU_PROPERTY_AARCH64_FEATURE_1_PAC
Definition ELF.h:1861
@ GNU_PROPERTY_AARCH64_FEATURE_1_GCS
Definition ELF.h:1862
@ SHT_PROGBITS
Definition ELF.h:1148
@ S_REGULAR
S_REGULAR - Regular section.
Definition MachO.h:127
void emitInstruction(MCObjectStreamer &, const MCInst &Inst, const MCSubtargetInfo &STI)
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract_or_null(Y &&MD)
Extract a Value from Metadata, allowing null.
Definition Metadata.h:683
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
bool empty() const
Definition BasicBlock.h:101
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:532
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
LLVM_ABI std::optional< std::string > getArm64ECMangledFunctionName(StringRef Name)
Returns the ARM64EC mangled function name unless the input is already mangled.
Definition Mangler.cpp:292
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1669
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:165
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
scope_exit(Callable) -> scope_exit< Callable >
static unsigned getXPACOpcodeForKey(AArch64PACKey::ID K)
Return XPAC opcode to be used for a ptrauth strip using the given key.
ExceptionHandling
Definition CodeGen.h:53
Target & getTheAArch64beTarget()
std::string utostr(uint64_t X, bool isNeg=false)
static unsigned getBranchOpcodeForKey(bool IsCall, AArch64PACKey::ID K, bool Zero)
Return B(L)RA opcode to be used for an authenticated branch or call using the given key,...
Target & getTheAArch64leTarget()
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
Target & getTheAArch64_32Target()
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:189
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Target & getTheARM64_32Target()
static MCRegister getXRegFromWReg(MCRegister Reg)
@ Add
Sum of integers.
Target & getTheARM64Target()
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
static MCRegister getXRegFromXRegTuple(MCRegister RegTuple)
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 MCRegister getWRegFromXReg(MCRegister Reg)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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
@ MCSA_WeakAntiDep
.weak_anti_dep (COFF)
@ MCSA_ELF_TypeFunction
.type _foo, STT_FUNC # aka @function
@ MCSA_Hidden
.hidden (ELF)
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
#define EQ(a, b)
Definition regexec.c:65
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...