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