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