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