10b57cec5SDimitry Andric //===- AArch64AsmPrinter.cpp - AArch64 LLVM assembly writer ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a printer that converts from our internal representation
100b57cec5SDimitry Andric // of machine-dependent LLVM code to the AArch64 assembly language.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "AArch64.h"
150b57cec5SDimitry Andric #include "AArch64MCInstLower.h"
160b57cec5SDimitry Andric #include "AArch64MachineFunctionInfo.h"
170b57cec5SDimitry Andric #include "AArch64RegisterInfo.h"
180b57cec5SDimitry Andric #include "AArch64Subtarget.h"
190b57cec5SDimitry Andric #include "AArch64TargetObjectFile.h"
200b57cec5SDimitry Andric #include "MCTargetDesc/AArch64AddressingModes.h"
210b57cec5SDimitry Andric #include "MCTargetDesc/AArch64InstPrinter.h"
220b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCExpr.h"
230b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCTargetDesc.h"
240b57cec5SDimitry Andric #include "MCTargetDesc/AArch64TargetStreamer.h"
250b57cec5SDimitry Andric #include "TargetInfo/AArch64TargetInfo.h"
260b57cec5SDimitry Andric #include "Utils/AArch64BaseInfo.h"
270b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
280b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
290b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
300b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
310b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
320b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
335f757f3fSDimitry Andric #include "llvm/BinaryFormat/MachO.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
35e8d8bef9SDimitry Andric #include "llvm/CodeGen/FaultMaps.h"
360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
370b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
380b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
390b57cec5SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
400b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h"
410b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
420b57cec5SDimitry Andric #include "llvm/CodeGen/StackMaps.h"
430b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
440b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
450b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
460fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
470b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
480b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
490b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
500b57cec5SDimitry Andric #include "llvm/MC/MCInstBuilder.h"
510b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
525f757f3fSDimitry Andric #include "llvm/MC/MCSectionMachO.h"
530b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
540b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
55349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
560b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
575f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h"
580b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
590b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
600b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
6106c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
62e8d8bef9SDimitry Andric #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
630b57cec5SDimitry Andric #include <algorithm>
640b57cec5SDimitry Andric #include <cassert>
650b57cec5SDimitry Andric #include <cstdint>
660b57cec5SDimitry Andric #include <map>
670b57cec5SDimitry Andric #include <memory>
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric using namespace llvm;
700b57cec5SDimitry Andric
710fca6ea1SDimitry Andric enum PtrauthCheckMode { Default, Unchecked, Poison, Trap };
720fca6ea1SDimitry Andric static cl::opt<PtrauthCheckMode> PtrauthAuthChecks(
730fca6ea1SDimitry Andric "aarch64-ptrauth-auth-checks", cl::Hidden,
740fca6ea1SDimitry Andric cl::values(clEnumValN(Unchecked, "none", "don't test for failure"),
750fca6ea1SDimitry Andric clEnumValN(Poison, "poison", "poison on failure"),
760fca6ea1SDimitry Andric clEnumValN(Trap, "trap", "trap on failure")),
770fca6ea1SDimitry Andric cl::desc("Check pointer authentication auth/resign failures"),
780fca6ea1SDimitry Andric cl::init(Default));
790fca6ea1SDimitry Andric
800b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric namespace {
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric class AArch64AsmPrinter : public AsmPrinter {
850b57cec5SDimitry Andric AArch64MCInstLower MCInstLowering;
86e8d8bef9SDimitry Andric FaultMaps FM;
870b57cec5SDimitry Andric const AArch64Subtarget *STI;
880eae32dcSDimitry Andric bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false;
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric public:
AArch64AsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)910b57cec5SDimitry Andric AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
920b57cec5SDimitry Andric : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
93bdd1243dSDimitry Andric FM(*this) {}
940b57cec5SDimitry Andric
getPassName() const950b57cec5SDimitry Andric StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric /// Wrapper for MCInstLowering.lowerOperand() for the
980b57cec5SDimitry Andric /// tblgen'erated pseudo lowering.
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const990b57cec5SDimitry Andric bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
1000b57cec5SDimitry Andric return MCInstLowering.lowerOperand(MO, MCOp);
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
1030fca6ea1SDimitry Andric const MCExpr *lowerConstantPtrAuth(const ConstantPtrAuth &CPA) override;
1040fca6ea1SDimitry Andric
1050fca6ea1SDimitry Andric const MCExpr *lowerBlockAddressConstant(const BlockAddress &BA) override;
1060fca6ea1SDimitry Andric
1075ffd83dbSDimitry Andric void emitStartOfAsmFile(Module &M) override;
1085ffd83dbSDimitry Andric void emitJumpTableInfo() override;
1095f757f3fSDimitry Andric std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
1105f757f3fSDimitry Andric codeview::JumpTableEntrySize>
1115f757f3fSDimitry Andric getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
1125f757f3fSDimitry Andric const MCSymbol *BranchLabel) const override;
1130b57cec5SDimitry Andric
114eaeb601bSDimitry Andric void emitFunctionEntryLabel() override;
115eaeb601bSDimitry Andric
116e8d8bef9SDimitry Andric void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
1170b57cec5SDimitry Andric
1180fca6ea1SDimitry Andric void LowerHardenedBRJumpTable(const MachineInstr &MI);
1190fca6ea1SDimitry Andric
1201fd87a68SDimitry Andric void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI);
1211fd87a68SDimitry Andric
1220b57cec5SDimitry Andric void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1230b57cec5SDimitry Andric const MachineInstr &MI);
1240b57cec5SDimitry Andric void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1250b57cec5SDimitry Andric const MachineInstr &MI);
126e8d8bef9SDimitry Andric void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
127e8d8bef9SDimitry Andric const MachineInstr &MI);
128e8d8bef9SDimitry Andric void LowerFAULTING_OP(const MachineInstr &MI);
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
1310b57cec5SDimitry Andric void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
1320b57cec5SDimitry Andric void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
13306c3fb27SDimitry Andric void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
1340b57cec5SDimitry Andric
1350fca6ea1SDimitry Andric typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
1360fca6ea1SDimitry Andric HwasanMemaccessTuple;
1378bcb0991SDimitry Andric std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
138bdd1243dSDimitry Andric void LowerKCFI_CHECK(const MachineInstr &MI);
1390b57cec5SDimitry Andric void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
140fe6060f1SDimitry Andric void emitHwasanMemaccessSymbols(Module &M);
1410b57cec5SDimitry Andric
142fe6060f1SDimitry Andric void emitSled(const MachineInstr &MI, SledKind Kind);
1430b57cec5SDimitry Andric
1440fca6ea1SDimitry Andric // Emit the sequence for BRA/BLRA (authenticate + branch/call).
1450fca6ea1SDimitry Andric void emitPtrauthBranch(const MachineInstr *MI);
1460fca6ea1SDimitry Andric
1470fca6ea1SDimitry Andric // Emit the sequence for AUT or AUTPAC.
1480fca6ea1SDimitry Andric void emitPtrauthAuthResign(const MachineInstr *MI);
1490fca6ea1SDimitry Andric
1500fca6ea1SDimitry Andric // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc.
1510fca6ea1SDimitry Andric unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc,
1520fca6ea1SDimitry Andric unsigned &InstsEmitted);
1530fca6ea1SDimitry Andric
1540fca6ea1SDimitry Andric // Emit the sequence for LOADauthptrstatic
1550fca6ea1SDimitry Andric void LowerLOADauthptrstatic(const MachineInstr &MI);
1560fca6ea1SDimitry Andric
1570fca6ea1SDimitry Andric // Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or
1580fca6ea1SDimitry Andric // adrp-add followed by PAC sign)
1590fca6ea1SDimitry Andric void LowerMOVaddrPAC(const MachineInstr &MI);
1600fca6ea1SDimitry Andric
1610b57cec5SDimitry Andric /// tblgen'erated driver function for lowering simple MI->MC
1620b57cec5SDimitry Andric /// pseudo instructions.
1630b57cec5SDimitry Andric bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
1640b57cec5SDimitry Andric const MachineInstr *MI);
1650b57cec5SDimitry Andric
1665ffd83dbSDimitry Andric void emitInstruction(const MachineInstr *MI) override;
1675ffd83dbSDimitry Andric
1685ffd83dbSDimitry Andric void emitFunctionHeaderComment() override;
1690b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const1700b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
1710b57cec5SDimitry Andric AsmPrinter::getAnalysisUsage(AU);
1720b57cec5SDimitry Andric AU.setPreservesAll();
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric
runOnMachineFunction(MachineFunction & MF)1750b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override {
1760b57cec5SDimitry Andric AArch64FI = MF.getInfo<AArch64FunctionInfo>();
17781ad6265SDimitry Andric STI = &MF.getSubtarget<AArch64Subtarget>();
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric SetupMachineFunction(MF);
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric if (STI->isTargetCOFF()) {
1825f757f3fSDimitry Andric bool Local = MF.getFunction().hasLocalLinkage();
1835f757f3fSDimitry Andric COFF::SymbolStorageClass Scl =
1845f757f3fSDimitry Andric Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL;
1850b57cec5SDimitry Andric int Type =
1860b57cec5SDimitry Andric COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
1870b57cec5SDimitry Andric
18881ad6265SDimitry Andric OutStreamer->beginCOFFSymbolDef(CurrentFnSym);
18981ad6265SDimitry Andric OutStreamer->emitCOFFSymbolStorageClass(Scl);
19081ad6265SDimitry Andric OutStreamer->emitCOFFSymbolType(Type);
19181ad6265SDimitry Andric OutStreamer->endCOFFSymbolDef();
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric // Emit the rest of the function body.
1955ffd83dbSDimitry Andric emitFunctionBody();
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric // Emit the XRay table for this function.
1980b57cec5SDimitry Andric emitXRayTable();
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric // We didn't modify anything.
2010b57cec5SDimitry Andric return false;
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric
2047a6dacacSDimitry Andric const MCExpr *lowerConstant(const Constant *CV) override;
2057a6dacacSDimitry Andric
2060b57cec5SDimitry Andric private:
2070b57cec5SDimitry Andric void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
2080b57cec5SDimitry Andric bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
2090b57cec5SDimitry Andric bool printAsmRegInClass(const MachineOperand &MO,
2108bcb0991SDimitry Andric const TargetRegisterClass *RC, unsigned AltName,
2110b57cec5SDimitry Andric raw_ostream &O);
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
2140b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) override;
2150b57cec5SDimitry Andric bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
2160b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) override;
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
2190b57cec5SDimitry Andric
2205ffd83dbSDimitry Andric void emitFunctionBodyEnd() override;
2210fca6ea1SDimitry Andric void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric MCSymbol *GetCPISymbol(unsigned CPID) const override;
2245ffd83dbSDimitry Andric void emitEndOfAsmFile(Module &M) override;
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric AArch64FunctionInfo *AArch64FI = nullptr;
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric /// Emit the LOHs contained in AArch64FI.
229fe6060f1SDimitry Andric void emitLOHs();
2300b57cec5SDimitry Andric
2310b57cec5SDimitry Andric /// Emit instruction to set float register to zero.
232fe6060f1SDimitry Andric void emitFMov0(const MachineInstr &MI);
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric MInstToMCSymbol LOHInstToLabel;
2370eae32dcSDimitry Andric
shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const2380eae32dcSDimitry Andric bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
2390eae32dcSDimitry Andric return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
2400eae32dcSDimitry Andric }
2415f757f3fSDimitry Andric
getIFuncMCSubtargetInfo() const2425f757f3fSDimitry Andric const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override {
2435f757f3fSDimitry Andric assert(STI);
2445f757f3fSDimitry Andric return STI;
2455f757f3fSDimitry Andric }
2465f757f3fSDimitry Andric void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
2475f757f3fSDimitry Andric MCSymbol *LazyPointer) override;
2485f757f3fSDimitry Andric void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI,
2495f757f3fSDimitry Andric MCSymbol *LazyPointer) override;
2500b57cec5SDimitry Andric };
2510b57cec5SDimitry Andric
2520b57cec5SDimitry Andric } // end anonymous namespace
2530b57cec5SDimitry Andric
emitStartOfAsmFile(Module & M)2545ffd83dbSDimitry Andric void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
255fe6060f1SDimitry Andric const Triple &TT = TM.getTargetTriple();
256fe6060f1SDimitry Andric
257fe6060f1SDimitry Andric if (TT.isOSBinFormatCOFF()) {
258bdd1243dSDimitry Andric // Emit an absolute @feat.00 symbol
259fe6060f1SDimitry Andric MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00"));
26081ad6265SDimitry Andric OutStreamer->beginCOFFSymbolDef(S);
26181ad6265SDimitry Andric OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
26281ad6265SDimitry Andric OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL);
26381ad6265SDimitry Andric OutStreamer->endCOFFSymbolDef();
264bdd1243dSDimitry Andric int64_t Feat00Value = 0;
265fe6060f1SDimitry Andric
266fe6060f1SDimitry Andric if (M.getModuleFlag("cfguard")) {
267bdd1243dSDimitry Andric // Object is CFG-aware.
268bdd1243dSDimitry Andric Feat00Value |= COFF::Feat00Flags::GuardCF;
269fe6060f1SDimitry Andric }
270fe6060f1SDimitry Andric
271fe6060f1SDimitry Andric if (M.getModuleFlag("ehcontguard")) {
272bdd1243dSDimitry Andric // Object also has EHCont.
273bdd1243dSDimitry Andric Feat00Value |= COFF::Feat00Flags::GuardEHCont;
274bdd1243dSDimitry Andric }
275bdd1243dSDimitry Andric
276bdd1243dSDimitry Andric if (M.getModuleFlag("ms-kernel")) {
277bdd1243dSDimitry Andric // Object is compiled with /kernel.
278bdd1243dSDimitry Andric Feat00Value |= COFF::Feat00Flags::Kernel;
279fe6060f1SDimitry Andric }
280fe6060f1SDimitry Andric
281fe6060f1SDimitry Andric OutStreamer->emitSymbolAttribute(S, MCSA_Global);
282fe6060f1SDimitry Andric OutStreamer->emitAssignment(
283bdd1243dSDimitry Andric S, MCConstantExpr::create(Feat00Value, MMI->getContext()));
284fe6060f1SDimitry Andric }
285fe6060f1SDimitry Andric
286fe6060f1SDimitry Andric if (!TT.isOSBinFormatELF())
287480093f4SDimitry Andric return;
288480093f4SDimitry Andric
289480093f4SDimitry Andric // Assemble feature flags that may require creation of a note section.
290e8d8bef9SDimitry Andric unsigned Flags = 0;
291e8d8bef9SDimitry Andric if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
292e8d8bef9SDimitry Andric M.getModuleFlag("branch-target-enforcement")))
2930fca6ea1SDimitry Andric if (!BTE->isZero())
294e8d8bef9SDimitry Andric Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
295480093f4SDimitry Andric
296297eecfbSDimitry Andric if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
297297eecfbSDimitry Andric M.getModuleFlag("guarded-control-stack")))
2980fca6ea1SDimitry Andric if (!GCS->isZero())
299297eecfbSDimitry Andric Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
300297eecfbSDimitry Andric
301e8d8bef9SDimitry Andric if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
302e8d8bef9SDimitry Andric M.getModuleFlag("sign-return-address")))
3030fca6ea1SDimitry Andric if (!Sign->isZero())
304e8d8bef9SDimitry Andric Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
305480093f4SDimitry Andric
3060fca6ea1SDimitry Andric uint64_t PAuthABIPlatform = -1;
3070fca6ea1SDimitry Andric if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
3080fca6ea1SDimitry Andric M.getModuleFlag("aarch64-elf-pauthabi-platform")))
3090fca6ea1SDimitry Andric PAuthABIPlatform = PAP->getZExtValue();
3100fca6ea1SDimitry Andric uint64_t PAuthABIVersion = -1;
3110fca6ea1SDimitry Andric if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
3120fca6ea1SDimitry Andric M.getModuleFlag("aarch64-elf-pauthabi-version")))
3130fca6ea1SDimitry Andric PAuthABIVersion = PAV->getZExtValue();
314480093f4SDimitry Andric
315480093f4SDimitry Andric // Emit a .note.gnu.property section with the flags.
316bdd1243dSDimitry Andric auto *TS =
317bdd1243dSDimitry Andric static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
3180fca6ea1SDimitry Andric TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion);
319480093f4SDimitry Andric }
320480093f4SDimitry Andric
emitFunctionHeaderComment()3215ffd83dbSDimitry Andric void AArch64AsmPrinter::emitFunctionHeaderComment() {
3225ffd83dbSDimitry Andric const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>();
323bdd1243dSDimitry Andric std::optional<std::string> OutlinerString = FI->getOutliningStyle();
324bdd1243dSDimitry Andric if (OutlinerString != std::nullopt)
32581ad6265SDimitry Andric OutStreamer->getCommentOS() << ' ' << OutlinerString;
3265ffd83dbSDimitry Andric }
3275ffd83dbSDimitry Andric
LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr & MI)3280b57cec5SDimitry Andric void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
3290b57cec5SDimitry Andric {
330480093f4SDimitry Andric const Function &F = MF->getFunction();
331480093f4SDimitry Andric if (F.hasFnAttribute("patchable-function-entry")) {
332480093f4SDimitry Andric unsigned Num;
333480093f4SDimitry Andric if (F.getFnAttribute("patchable-function-entry")
334480093f4SDimitry Andric .getValueAsString()
335480093f4SDimitry Andric .getAsInteger(10, Num))
336480093f4SDimitry Andric return;
33755e4f9d5SDimitry Andric emitNops(Num);
338480093f4SDimitry Andric return;
339480093f4SDimitry Andric }
340480093f4SDimitry Andric
341fe6060f1SDimitry Andric emitSled(MI, SledKind::FUNCTION_ENTER);
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric
LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr & MI)344fe6060f1SDimitry Andric void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
345fe6060f1SDimitry Andric emitSled(MI, SledKind::FUNCTION_EXIT);
3460b57cec5SDimitry Andric }
3470b57cec5SDimitry Andric
LowerPATCHABLE_TAIL_CALL(const MachineInstr & MI)348fe6060f1SDimitry Andric void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
349fe6060f1SDimitry Andric emitSled(MI, SledKind::TAIL_CALL);
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric
emitSled(const MachineInstr & MI,SledKind Kind)352fe6060f1SDimitry Andric void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
3530b57cec5SDimitry Andric static const int8_t NoopsInSledCount = 7;
3540b57cec5SDimitry Andric // We want to emit the following pattern:
3550b57cec5SDimitry Andric //
3560b57cec5SDimitry Andric // .Lxray_sled_N:
3570b57cec5SDimitry Andric // ALIGN
3580b57cec5SDimitry Andric // B #32
3590b57cec5SDimitry Andric // ; 7 NOP instructions (28 bytes)
3600b57cec5SDimitry Andric // .tmpN
3610b57cec5SDimitry Andric //
3620b57cec5SDimitry Andric // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
3630b57cec5SDimitry Andric // over the full 32 bytes (8 instructions) with the following pattern:
3640b57cec5SDimitry Andric //
3650b57cec5SDimitry Andric // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
36606c3fb27SDimitry Andric // LDR W17, #12 ; W17 := function ID
3670b57cec5SDimitry Andric // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
3680b57cec5SDimitry Andric // BLR X16 ; call the tracing trampoline
3690b57cec5SDimitry Andric // ;DATA: 32 bits of function ID
3700b57cec5SDimitry Andric // ;DATA: lower 32 bits of the address of the trampoline
3710b57cec5SDimitry Andric // ;DATA: higher 32 bits of the address of the trampoline
3720b57cec5SDimitry Andric // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
3730b57cec5SDimitry Andric //
374bdd1243dSDimitry Andric OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
3750b57cec5SDimitry Andric auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
3765ffd83dbSDimitry Andric OutStreamer->emitLabel(CurSled);
3770b57cec5SDimitry Andric auto Target = OutContext.createTempSymbol();
3780b57cec5SDimitry Andric
3790b57cec5SDimitry Andric // Emit "B #32" instruction, which jumps over the next 28 bytes.
3800b57cec5SDimitry Andric // The operand has to be the number of 4-byte instructions to jump over,
3810b57cec5SDimitry Andric // including the current instruction.
3820b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric for (int8_t I = 0; I < NoopsInSledCount; I++)
3850b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
3860b57cec5SDimitry Andric
3875ffd83dbSDimitry Andric OutStreamer->emitLabel(Target);
3885ffd83dbSDimitry Andric recordSled(CurSled, MI, Kind, 2);
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric
39106c3fb27SDimitry Andric // Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
39206c3fb27SDimitry Andric // (built-in functions __xray_customevent/__xray_typedevent).
39306c3fb27SDimitry Andric //
39406c3fb27SDimitry Andric // .Lxray_event_sled_N:
39506c3fb27SDimitry Andric // b 1f
39606c3fb27SDimitry Andric // save x0 and x1 (and also x2 for TYPED_EVENT_CALL)
39706c3fb27SDimitry Andric // set up x0 and x1 (and also x2 for TYPED_EVENT_CALL)
39806c3fb27SDimitry Andric // bl __xray_CustomEvent or __xray_TypedEvent
39906c3fb27SDimitry Andric // restore x0 and x1 (and also x2 for TYPED_EVENT_CALL)
40006c3fb27SDimitry Andric // 1:
40106c3fb27SDimitry Andric //
40206c3fb27SDimitry Andric // There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL.
40306c3fb27SDimitry Andric //
40406c3fb27SDimitry Andric // Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT.
40506c3fb27SDimitry Andric // After patching, b .+N will become a nop.
LowerPATCHABLE_EVENT_CALL(const MachineInstr & MI,bool Typed)40606c3fb27SDimitry Andric void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
40706c3fb27SDimitry Andric bool Typed) {
40806c3fb27SDimitry Andric auto &O = *OutStreamer;
40906c3fb27SDimitry Andric MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true);
41006c3fb27SDimitry Andric O.emitLabel(CurSled);
41106c3fb27SDimitry Andric MCInst MovX0Op0 = MCInstBuilder(AArch64::ORRXrs)
41206c3fb27SDimitry Andric .addReg(AArch64::X0)
41306c3fb27SDimitry Andric .addReg(AArch64::XZR)
41406c3fb27SDimitry Andric .addReg(MI.getOperand(0).getReg())
41506c3fb27SDimitry Andric .addImm(0);
41606c3fb27SDimitry Andric MCInst MovX1Op1 = MCInstBuilder(AArch64::ORRXrs)
41706c3fb27SDimitry Andric .addReg(AArch64::X1)
41806c3fb27SDimitry Andric .addReg(AArch64::XZR)
41906c3fb27SDimitry Andric .addReg(MI.getOperand(1).getReg())
42006c3fb27SDimitry Andric .addImm(0);
42106c3fb27SDimitry Andric bool MachO = TM.getTargetTriple().isOSBinFormatMachO();
42206c3fb27SDimitry Andric auto *Sym = MCSymbolRefExpr::create(
42306c3fb27SDimitry Andric OutContext.getOrCreateSymbol(
42406c3fb27SDimitry Andric Twine(MachO ? "_" : "") +
42506c3fb27SDimitry Andric (Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")),
42606c3fb27SDimitry Andric OutContext);
42706c3fb27SDimitry Andric if (Typed) {
42806c3fb27SDimitry Andric O.AddComment("Begin XRay typed event");
42906c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9));
43006c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
43106c3fb27SDimitry Andric .addReg(AArch64::SP)
43206c3fb27SDimitry Andric .addReg(AArch64::X0)
43306c3fb27SDimitry Andric .addReg(AArch64::X1)
43406c3fb27SDimitry Andric .addReg(AArch64::SP)
43506c3fb27SDimitry Andric .addImm(-4));
43606c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::STRXui)
43706c3fb27SDimitry Andric .addReg(AArch64::X2)
43806c3fb27SDimitry Andric .addReg(AArch64::SP)
43906c3fb27SDimitry Andric .addImm(2));
44006c3fb27SDimitry Andric EmitToStreamer(O, MovX0Op0);
44106c3fb27SDimitry Andric EmitToStreamer(O, MovX1Op1);
44206c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::ORRXrs)
44306c3fb27SDimitry Andric .addReg(AArch64::X2)
44406c3fb27SDimitry Andric .addReg(AArch64::XZR)
44506c3fb27SDimitry Andric .addReg(MI.getOperand(2).getReg())
44606c3fb27SDimitry Andric .addImm(0));
44706c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
44806c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui)
44906c3fb27SDimitry Andric .addReg(AArch64::X2)
45006c3fb27SDimitry Andric .addReg(AArch64::SP)
45106c3fb27SDimitry Andric .addImm(2));
45206c3fb27SDimitry Andric O.AddComment("End XRay typed event");
45306c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
45406c3fb27SDimitry Andric .addReg(AArch64::SP)
45506c3fb27SDimitry Andric .addReg(AArch64::X0)
45606c3fb27SDimitry Andric .addReg(AArch64::X1)
45706c3fb27SDimitry Andric .addReg(AArch64::SP)
45806c3fb27SDimitry Andric .addImm(4));
45906c3fb27SDimitry Andric
46006c3fb27SDimitry Andric recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2);
46106c3fb27SDimitry Andric } else {
46206c3fb27SDimitry Andric O.AddComment("Begin XRay custom event");
46306c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6));
46406c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre)
46506c3fb27SDimitry Andric .addReg(AArch64::SP)
46606c3fb27SDimitry Andric .addReg(AArch64::X0)
46706c3fb27SDimitry Andric .addReg(AArch64::X1)
46806c3fb27SDimitry Andric .addReg(AArch64::SP)
46906c3fb27SDimitry Andric .addImm(-2));
47006c3fb27SDimitry Andric EmitToStreamer(O, MovX0Op0);
47106c3fb27SDimitry Andric EmitToStreamer(O, MovX1Op1);
47206c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym));
47306c3fb27SDimitry Andric O.AddComment("End XRay custom event");
47406c3fb27SDimitry Andric EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost)
47506c3fb27SDimitry Andric .addReg(AArch64::SP)
47606c3fb27SDimitry Andric .addReg(AArch64::X0)
47706c3fb27SDimitry Andric .addReg(AArch64::X1)
47806c3fb27SDimitry Andric .addReg(AArch64::SP)
47906c3fb27SDimitry Andric .addImm(2));
48006c3fb27SDimitry Andric
48106c3fb27SDimitry Andric recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2);
48206c3fb27SDimitry Andric }
48306c3fb27SDimitry Andric }
48406c3fb27SDimitry Andric
LowerKCFI_CHECK(const MachineInstr & MI)485bdd1243dSDimitry Andric void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
486bdd1243dSDimitry Andric Register AddrReg = MI.getOperand(0).getReg();
487bdd1243dSDimitry Andric assert(std::next(MI.getIterator())->isCall() &&
488bdd1243dSDimitry Andric "KCFI_CHECK not followed by a call instruction");
489bdd1243dSDimitry Andric assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
490bdd1243dSDimitry Andric "KCFI_CHECK call target doesn't match call operand");
491bdd1243dSDimitry Andric
492bdd1243dSDimitry Andric // Default to using the intra-procedure-call temporary registers for
493bdd1243dSDimitry Andric // comparing the hashes.
494bdd1243dSDimitry Andric unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
495bdd1243dSDimitry Andric if (AddrReg == AArch64::XZR) {
496bdd1243dSDimitry Andric // Checking XZR makes no sense. Instead of emitting a load, zero
497bdd1243dSDimitry Andric // ScratchRegs[0] and use it for the ESR AddrIndex below.
498bdd1243dSDimitry Andric AddrReg = getXRegFromWReg(ScratchRegs[0]);
499bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
500bdd1243dSDimitry Andric .addReg(AddrReg)
501bdd1243dSDimitry Andric .addReg(AArch64::XZR)
502bdd1243dSDimitry Andric .addReg(AArch64::XZR)
503bdd1243dSDimitry Andric .addImm(0));
504bdd1243dSDimitry Andric } else {
505bdd1243dSDimitry Andric // If one of the scratch registers is used for the call target (e.g.
506bdd1243dSDimitry Andric // with AArch64::TCRETURNriBTI), we can clobber another caller-saved
507bdd1243dSDimitry Andric // temporary register instead (in this case, AArch64::W9) as the check
508bdd1243dSDimitry Andric // is immediately followed by the call instruction.
509bdd1243dSDimitry Andric for (auto &Reg : ScratchRegs) {
510bdd1243dSDimitry Andric if (Reg == getWRegFromXReg(AddrReg)) {
511bdd1243dSDimitry Andric Reg = AArch64::W9;
512bdd1243dSDimitry Andric break;
513bdd1243dSDimitry Andric }
514bdd1243dSDimitry Andric }
515bdd1243dSDimitry Andric assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
516bdd1243dSDimitry Andric "Invalid scratch registers for KCFI_CHECK");
517bdd1243dSDimitry Andric
518bdd1243dSDimitry Andric // Adjust the offset for patchable-function-prefix. This assumes that
519bdd1243dSDimitry Andric // patchable-function-prefix is the same for all functions.
520bdd1243dSDimitry Andric int64_t PrefixNops = 0;
521bdd1243dSDimitry Andric (void)MI.getMF()
522bdd1243dSDimitry Andric ->getFunction()
523bdd1243dSDimitry Andric .getFnAttribute("patchable-function-prefix")
524bdd1243dSDimitry Andric .getValueAsString()
525bdd1243dSDimitry Andric .getAsInteger(10, PrefixNops);
526bdd1243dSDimitry Andric
527bdd1243dSDimitry Andric // Load the target function type hash.
528bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
529bdd1243dSDimitry Andric .addReg(ScratchRegs[0])
530bdd1243dSDimitry Andric .addReg(AddrReg)
531bdd1243dSDimitry Andric .addImm(-(PrefixNops * 4 + 4)));
532bdd1243dSDimitry Andric }
533bdd1243dSDimitry Andric
534bdd1243dSDimitry Andric // Load the expected type hash.
535bdd1243dSDimitry Andric const int64_t Type = MI.getOperand(1).getImm();
536bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
537bdd1243dSDimitry Andric .addReg(ScratchRegs[1])
538bdd1243dSDimitry Andric .addReg(ScratchRegs[1])
539bdd1243dSDimitry Andric .addImm(Type & 0xFFFF)
540bdd1243dSDimitry Andric .addImm(0));
541bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi)
542bdd1243dSDimitry Andric .addReg(ScratchRegs[1])
543bdd1243dSDimitry Andric .addReg(ScratchRegs[1])
544bdd1243dSDimitry Andric .addImm((Type >> 16) & 0xFFFF)
545bdd1243dSDimitry Andric .addImm(16));
546bdd1243dSDimitry Andric
547bdd1243dSDimitry Andric // Compare the hashes and trap if there's a mismatch.
548bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs)
549bdd1243dSDimitry Andric .addReg(AArch64::WZR)
550bdd1243dSDimitry Andric .addReg(ScratchRegs[0])
551bdd1243dSDimitry Andric .addReg(ScratchRegs[1])
552bdd1243dSDimitry Andric .addImm(0));
553bdd1243dSDimitry Andric
554bdd1243dSDimitry Andric MCSymbol *Pass = OutContext.createTempSymbol();
555bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer,
556bdd1243dSDimitry Andric MCInstBuilder(AArch64::Bcc)
557bdd1243dSDimitry Andric .addImm(AArch64CC::EQ)
558bdd1243dSDimitry Andric .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
559bdd1243dSDimitry Andric
560bdd1243dSDimitry Andric // The base ESR is 0x8000 and the register information is encoded in bits
561bdd1243dSDimitry Andric // 0-9 as follows:
562bdd1243dSDimitry Andric // - 0-4: n, where the register Xn contains the target address
563bdd1243dSDimitry Andric // - 5-9: m, where the register Wm contains the expected type hash
564bdd1243dSDimitry Andric // Where n, m are in [0, 30].
565bdd1243dSDimitry Andric unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
566bdd1243dSDimitry Andric unsigned AddrIndex;
567bdd1243dSDimitry Andric switch (AddrReg) {
568bdd1243dSDimitry Andric default:
569bdd1243dSDimitry Andric AddrIndex = AddrReg - AArch64::X0;
570bdd1243dSDimitry Andric break;
571bdd1243dSDimitry Andric case AArch64::FP:
572bdd1243dSDimitry Andric AddrIndex = 29;
573bdd1243dSDimitry Andric break;
574bdd1243dSDimitry Andric case AArch64::LR:
575bdd1243dSDimitry Andric AddrIndex = 30;
576bdd1243dSDimitry Andric break;
577bdd1243dSDimitry Andric }
578bdd1243dSDimitry Andric
579bdd1243dSDimitry Andric assert(AddrIndex < 31 && TypeIndex < 31);
580bdd1243dSDimitry Andric
581bdd1243dSDimitry Andric unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
582bdd1243dSDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR));
583bdd1243dSDimitry Andric OutStreamer->emitLabel(Pass);
584bdd1243dSDimitry Andric }
585bdd1243dSDimitry Andric
LowerHWASAN_CHECK_MEMACCESS(const MachineInstr & MI)5860b57cec5SDimitry Andric void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
5878bcb0991SDimitry Andric Register Reg = MI.getOperand(0).getReg();
5888bcb0991SDimitry Andric bool IsShort =
5890fca6ea1SDimitry Andric ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
5900fca6ea1SDimitry Andric (MI.getOpcode() ==
5910fca6ea1SDimitry Andric AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
5920b57cec5SDimitry Andric uint32_t AccessInfo = MI.getOperand(1).getImm();
5930fca6ea1SDimitry Andric bool IsFixedShadow =
5940fca6ea1SDimitry Andric ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
5950fca6ea1SDimitry Andric (MI.getOpcode() ==
5960fca6ea1SDimitry Andric AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
5970fca6ea1SDimitry Andric uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0;
5980fca6ea1SDimitry Andric
5990fca6ea1SDimitry Andric MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
6000fca6ea1SDimitry Andric Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
6010b57cec5SDimitry Andric if (!Sym) {
6020b57cec5SDimitry Andric // FIXME: Make this work on non-ELF.
6030b57cec5SDimitry Andric if (!TM.getTargetTriple().isOSBinFormatELF())
6040b57cec5SDimitry Andric report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
6050b57cec5SDimitry Andric
6060b57cec5SDimitry Andric std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
6070b57cec5SDimitry Andric utostr(AccessInfo);
6080fca6ea1SDimitry Andric if (IsFixedShadow)
6090fca6ea1SDimitry Andric SymName += "_fixed_" + utostr(FixedShadowOffset);
6108bcb0991SDimitry Andric if (IsShort)
611e8d8bef9SDimitry Andric SymName += "_short_v2";
6120b57cec5SDimitry Andric Sym = OutContext.getOrCreateSymbol(SymName);
6130b57cec5SDimitry Andric }
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric EmitToStreamer(*OutStreamer,
6160b57cec5SDimitry Andric MCInstBuilder(AArch64::BL)
6170b57cec5SDimitry Andric .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric
emitHwasanMemaccessSymbols(Module & M)620fe6060f1SDimitry Andric void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
6210b57cec5SDimitry Andric if (HwasanMemaccessSymbols.empty())
6220b57cec5SDimitry Andric return;
6230b57cec5SDimitry Andric
6240b57cec5SDimitry Andric const Triple &TT = TM.getTargetTriple();
6250b57cec5SDimitry Andric assert(TT.isOSBinFormatELF());
6260b57cec5SDimitry Andric std::unique_ptr<MCSubtargetInfo> STI(
6270b57cec5SDimitry Andric TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
628e8d8bef9SDimitry Andric assert(STI && "Unable to create subtarget info");
6290b57cec5SDimitry Andric
6308bcb0991SDimitry Andric MCSymbol *HwasanTagMismatchV1Sym =
6310b57cec5SDimitry Andric OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
6328bcb0991SDimitry Andric MCSymbol *HwasanTagMismatchV2Sym =
6338bcb0991SDimitry Andric OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
6340b57cec5SDimitry Andric
6358bcb0991SDimitry Andric const MCSymbolRefExpr *HwasanTagMismatchV1Ref =
6368bcb0991SDimitry Andric MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext);
6378bcb0991SDimitry Andric const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
6388bcb0991SDimitry Andric MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
6390b57cec5SDimitry Andric
6400b57cec5SDimitry Andric for (auto &P : HwasanMemaccessSymbols) {
6418bcb0991SDimitry Andric unsigned Reg = std::get<0>(P.first);
6428bcb0991SDimitry Andric bool IsShort = std::get<1>(P.first);
6438bcb0991SDimitry Andric uint32_t AccessInfo = std::get<2>(P.first);
6440fca6ea1SDimitry Andric bool IsFixedShadow = std::get<3>(P.first);
6450fca6ea1SDimitry Andric uint64_t FixedShadowOffset = std::get<4>(P.first);
6468bcb0991SDimitry Andric const MCSymbolRefExpr *HwasanTagMismatchRef =
6478bcb0991SDimitry Andric IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
6480b57cec5SDimitry Andric MCSymbol *Sym = P.second;
6490b57cec5SDimitry Andric
650e8d8bef9SDimitry Andric bool HasMatchAllTag =
651e8d8bef9SDimitry Andric (AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1;
652e8d8bef9SDimitry Andric uint8_t MatchAllTag =
653e8d8bef9SDimitry Andric (AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff;
654e8d8bef9SDimitry Andric unsigned Size =
655e8d8bef9SDimitry Andric 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
656e8d8bef9SDimitry Andric bool CompileKernel =
657e8d8bef9SDimitry Andric (AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1;
658e8d8bef9SDimitry Andric
65981ad6265SDimitry Andric OutStreamer->switchSection(OutContext.getELFSection(
6600b57cec5SDimitry Andric ".text.hot", ELF::SHT_PROGBITS,
66181ad6265SDimitry Andric ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
66281ad6265SDimitry Andric /*IsComdat=*/true));
6630b57cec5SDimitry Andric
6645ffd83dbSDimitry Andric OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
6655ffd83dbSDimitry Andric OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
6665ffd83dbSDimitry Andric OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
6675ffd83dbSDimitry Andric OutStreamer->emitLabel(Sym);
6680b57cec5SDimitry Andric
669e8d8bef9SDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::SBFMXri)
6700b57cec5SDimitry Andric .addReg(AArch64::X16)
6710b57cec5SDimitry Andric .addReg(Reg)
6720b57cec5SDimitry Andric .addImm(4)
6730b57cec5SDimitry Andric .addImm(55),
6740b57cec5SDimitry Andric *STI);
6750fca6ea1SDimitry Andric
6760fca6ea1SDimitry Andric if (IsFixedShadow) {
6770fca6ea1SDimitry Andric // Aarch64 makes it difficult to embed large constants in the code.
6780fca6ea1SDimitry Andric // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit
6790fca6ea1SDimitry Andric // left-shift option in the MOV instruction. Combined with the 16-bit
6800fca6ea1SDimitry Andric // immediate, this is enough to represent any offset up to 2**48.
6810fca6ea1SDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
6820fca6ea1SDimitry Andric .addReg(AArch64::X17)
6830fca6ea1SDimitry Andric .addImm(FixedShadowOffset >> 32)
6840fca6ea1SDimitry Andric .addImm(32),
6850fca6ea1SDimitry Andric *STI);
6860fca6ea1SDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX)
6870fca6ea1SDimitry Andric .addReg(AArch64::W16)
6880fca6ea1SDimitry Andric .addReg(AArch64::X17)
6890fca6ea1SDimitry Andric .addReg(AArch64::X16)
6900fca6ea1SDimitry Andric .addImm(0)
6910fca6ea1SDimitry Andric .addImm(0),
6920fca6ea1SDimitry Andric *STI);
6930fca6ea1SDimitry Andric } else {
694e8d8bef9SDimitry Andric OutStreamer->emitInstruction(
695e8d8bef9SDimitry Andric MCInstBuilder(AArch64::LDRBBroX)
6960b57cec5SDimitry Andric .addReg(AArch64::W16)
697e8d8bef9SDimitry Andric .addReg(IsShort ? AArch64::X20 : AArch64::X9)
6980b57cec5SDimitry Andric .addReg(AArch64::X16)
6990b57cec5SDimitry Andric .addImm(0)
7000b57cec5SDimitry Andric .addImm(0),
7010b57cec5SDimitry Andric *STI);
7020fca6ea1SDimitry Andric }
7030fca6ea1SDimitry Andric
7045ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7050b57cec5SDimitry Andric MCInstBuilder(AArch64::SUBSXrs)
7060b57cec5SDimitry Andric .addReg(AArch64::XZR)
7070b57cec5SDimitry Andric .addReg(AArch64::X16)
7080b57cec5SDimitry Andric .addReg(Reg)
7090b57cec5SDimitry Andric .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSR, 56)),
7100b57cec5SDimitry Andric *STI);
7118bcb0991SDimitry Andric MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
7125ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7130b57cec5SDimitry Andric MCInstBuilder(AArch64::Bcc)
7140b57cec5SDimitry Andric .addImm(AArch64CC::NE)
7158bcb0991SDimitry Andric .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
7168bcb0991SDimitry Andric OutContext)),
7170b57cec5SDimitry Andric *STI);
7180b57cec5SDimitry Andric MCSymbol *ReturnSym = OutContext.createTempSymbol();
7195ffd83dbSDimitry Andric OutStreamer->emitLabel(ReturnSym);
7205ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7210b57cec5SDimitry Andric MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
7225ffd83dbSDimitry Andric OutStreamer->emitLabel(HandleMismatchOrPartialSym);
7230b57cec5SDimitry Andric
724e8d8bef9SDimitry Andric if (HasMatchAllTag) {
725e8d8bef9SDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::UBFMXri)
72606c3fb27SDimitry Andric .addReg(AArch64::X17)
727e8d8bef9SDimitry Andric .addReg(Reg)
728e8d8bef9SDimitry Andric .addImm(56)
729e8d8bef9SDimitry Andric .addImm(63),
730e8d8bef9SDimitry Andric *STI);
731e8d8bef9SDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSXri)
732e8d8bef9SDimitry Andric .addReg(AArch64::XZR)
73306c3fb27SDimitry Andric .addReg(AArch64::X17)
734e8d8bef9SDimitry Andric .addImm(MatchAllTag)
735e8d8bef9SDimitry Andric .addImm(0),
736e8d8bef9SDimitry Andric *STI);
737e8d8bef9SDimitry Andric OutStreamer->emitInstruction(
738e8d8bef9SDimitry Andric MCInstBuilder(AArch64::Bcc)
739e8d8bef9SDimitry Andric .addImm(AArch64CC::EQ)
740e8d8bef9SDimitry Andric .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
741e8d8bef9SDimitry Andric *STI);
742e8d8bef9SDimitry Andric }
743e8d8bef9SDimitry Andric
7448bcb0991SDimitry Andric if (IsShort) {
7455ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWri)
7460b57cec5SDimitry Andric .addReg(AArch64::WZR)
7470b57cec5SDimitry Andric .addReg(AArch64::W16)
7480b57cec5SDimitry Andric .addImm(15)
7490b57cec5SDimitry Andric .addImm(0),
7500b57cec5SDimitry Andric *STI);
7510b57cec5SDimitry Andric MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
7525ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7530b57cec5SDimitry Andric MCInstBuilder(AArch64::Bcc)
7540b57cec5SDimitry Andric .addImm(AArch64CC::HI)
7550b57cec5SDimitry Andric .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
7560b57cec5SDimitry Andric *STI);
7570b57cec5SDimitry Andric
7585ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7590b57cec5SDimitry Andric MCInstBuilder(AArch64::ANDXri)
7600b57cec5SDimitry Andric .addReg(AArch64::X17)
7610b57cec5SDimitry Andric .addReg(Reg)
7620b57cec5SDimitry Andric .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)),
7630b57cec5SDimitry Andric *STI);
7640b57cec5SDimitry Andric if (Size != 1)
7655ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
7660b57cec5SDimitry Andric .addReg(AArch64::X17)
7670b57cec5SDimitry Andric .addReg(AArch64::X17)
7680b57cec5SDimitry Andric .addImm(Size - 1)
7690b57cec5SDimitry Andric .addImm(0),
7700b57cec5SDimitry Andric *STI);
7715ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWrs)
7720b57cec5SDimitry Andric .addReg(AArch64::WZR)
7730b57cec5SDimitry Andric .addReg(AArch64::W16)
7740b57cec5SDimitry Andric .addReg(AArch64::W17)
7750b57cec5SDimitry Andric .addImm(0),
7760b57cec5SDimitry Andric *STI);
7775ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7780b57cec5SDimitry Andric MCInstBuilder(AArch64::Bcc)
7790b57cec5SDimitry Andric .addImm(AArch64CC::LS)
7800b57cec5SDimitry Andric .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
7810b57cec5SDimitry Andric *STI);
7820b57cec5SDimitry Andric
7835ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7840b57cec5SDimitry Andric MCInstBuilder(AArch64::ORRXri)
7850b57cec5SDimitry Andric .addReg(AArch64::X16)
7860b57cec5SDimitry Andric .addReg(Reg)
7870b57cec5SDimitry Andric .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)),
7880b57cec5SDimitry Andric *STI);
7895ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBui)
7900b57cec5SDimitry Andric .addReg(AArch64::W16)
7910b57cec5SDimitry Andric .addReg(AArch64::X16)
7920b57cec5SDimitry Andric .addImm(0),
7930b57cec5SDimitry Andric *STI);
7945ffd83dbSDimitry Andric OutStreamer->emitInstruction(
7950b57cec5SDimitry Andric MCInstBuilder(AArch64::SUBSXrs)
7960b57cec5SDimitry Andric .addReg(AArch64::XZR)
7970b57cec5SDimitry Andric .addReg(AArch64::X16)
7980b57cec5SDimitry Andric .addReg(Reg)
7990b57cec5SDimitry Andric .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSR, 56)),
8000b57cec5SDimitry Andric *STI);
8015ffd83dbSDimitry Andric OutStreamer->emitInstruction(
8020b57cec5SDimitry Andric MCInstBuilder(AArch64::Bcc)
8030b57cec5SDimitry Andric .addImm(AArch64CC::EQ)
8040b57cec5SDimitry Andric .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
8050b57cec5SDimitry Andric *STI);
8060b57cec5SDimitry Andric
8075ffd83dbSDimitry Andric OutStreamer->emitLabel(HandleMismatchSym);
8088bcb0991SDimitry Andric }
8098bcb0991SDimitry Andric
8105ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
8110b57cec5SDimitry Andric .addReg(AArch64::SP)
8120b57cec5SDimitry Andric .addReg(AArch64::X0)
8130b57cec5SDimitry Andric .addReg(AArch64::X1)
8140b57cec5SDimitry Andric .addReg(AArch64::SP)
8150b57cec5SDimitry Andric .addImm(-32),
8160b57cec5SDimitry Andric *STI);
8175ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
8180b57cec5SDimitry Andric .addReg(AArch64::FP)
8190b57cec5SDimitry Andric .addReg(AArch64::LR)
8200b57cec5SDimitry Andric .addReg(AArch64::SP)
8210b57cec5SDimitry Andric .addImm(29),
8220b57cec5SDimitry Andric *STI);
8230b57cec5SDimitry Andric
8240b57cec5SDimitry Andric if (Reg != AArch64::X0)
8255ffd83dbSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::ORRXrs)
8260b57cec5SDimitry Andric .addReg(AArch64::X0)
8270b57cec5SDimitry Andric .addReg(AArch64::XZR)
8280b57cec5SDimitry Andric .addReg(Reg)
8290b57cec5SDimitry Andric .addImm(0),
8300b57cec5SDimitry Andric *STI);
831e8d8bef9SDimitry Andric OutStreamer->emitInstruction(
832e8d8bef9SDimitry Andric MCInstBuilder(AArch64::MOVZXi)
8330b57cec5SDimitry Andric .addReg(AArch64::X1)
834e8d8bef9SDimitry Andric .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask)
8350b57cec5SDimitry Andric .addImm(0),
8360b57cec5SDimitry Andric *STI);
8370b57cec5SDimitry Andric
838e8d8bef9SDimitry Andric if (CompileKernel) {
839e8d8bef9SDimitry Andric // The Linux kernel's dynamic loader doesn't support GOT relative
840e8d8bef9SDimitry Andric // relocations, but it doesn't support late binding either, so just call
841e8d8bef9SDimitry Andric // the function directly.
842e8d8bef9SDimitry Andric OutStreamer->emitInstruction(
843e8d8bef9SDimitry Andric MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef), *STI);
844e8d8bef9SDimitry Andric } else {
8450b57cec5SDimitry Andric // Intentionally load the GOT entry and branch to it, rather than possibly
846e8d8bef9SDimitry Andric // late binding the function, which may clobber the registers before we
847e8d8bef9SDimitry Andric // have a chance to save them.
8485ffd83dbSDimitry Andric OutStreamer->emitInstruction(
8490b57cec5SDimitry Andric MCInstBuilder(AArch64::ADRP)
8500b57cec5SDimitry Andric .addReg(AArch64::X16)
8510b57cec5SDimitry Andric .addExpr(AArch64MCExpr::create(
8528bcb0991SDimitry Andric HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_PAGE,
8538bcb0991SDimitry Andric OutContext)),
8540b57cec5SDimitry Andric *STI);
8555ffd83dbSDimitry Andric OutStreamer->emitInstruction(
8560b57cec5SDimitry Andric MCInstBuilder(AArch64::LDRXui)
8570b57cec5SDimitry Andric .addReg(AArch64::X16)
8580b57cec5SDimitry Andric .addReg(AArch64::X16)
8590b57cec5SDimitry Andric .addExpr(AArch64MCExpr::create(
8608bcb0991SDimitry Andric HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_LO12,
8618bcb0991SDimitry Andric OutContext)),
8620b57cec5SDimitry Andric *STI);
8635ffd83dbSDimitry Andric OutStreamer->emitInstruction(
8640b57cec5SDimitry Andric MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI);
8650b57cec5SDimitry Andric }
8660b57cec5SDimitry Andric }
867e8d8bef9SDimitry Andric }
8680b57cec5SDimitry Andric
emitAuthenticatedPointer(MCStreamer & OutStreamer,MCSymbol * StubLabel,const MCExpr * StubAuthPtrRef)8690fca6ea1SDimitry Andric static void emitAuthenticatedPointer(MCStreamer &OutStreamer,
8700fca6ea1SDimitry Andric MCSymbol *StubLabel,
8710fca6ea1SDimitry Andric const MCExpr *StubAuthPtrRef) {
8720fca6ea1SDimitry Andric // sym$auth_ptr$key$disc:
8730fca6ea1SDimitry Andric OutStreamer.emitLabel(StubLabel);
8740fca6ea1SDimitry Andric OutStreamer.emitValue(StubAuthPtrRef, /*size=*/8);
8750fca6ea1SDimitry Andric }
8760fca6ea1SDimitry Andric
emitEndOfAsmFile(Module & M)8775ffd83dbSDimitry Andric void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
878fe6060f1SDimitry Andric emitHwasanMemaccessSymbols(M);
8790b57cec5SDimitry Andric
8800b57cec5SDimitry Andric const Triple &TT = TM.getTargetTriple();
8810b57cec5SDimitry Andric if (TT.isOSBinFormatMachO()) {
8820fca6ea1SDimitry Andric // Output authenticated pointers as indirect symbols, if we have any.
8830fca6ea1SDimitry Andric MachineModuleInfoMachO &MMIMacho =
8840fca6ea1SDimitry Andric MMI->getObjFileInfo<MachineModuleInfoMachO>();
8850fca6ea1SDimitry Andric
8860fca6ea1SDimitry Andric auto Stubs = MMIMacho.getAuthGVStubList();
8870fca6ea1SDimitry Andric
8880fca6ea1SDimitry Andric if (!Stubs.empty()) {
8890fca6ea1SDimitry Andric // Switch to the "__auth_ptr" section.
8900fca6ea1SDimitry Andric OutStreamer->switchSection(
8910fca6ea1SDimitry Andric OutContext.getMachOSection("__DATA", "__auth_ptr", MachO::S_REGULAR,
8920fca6ea1SDimitry Andric SectionKind::getMetadata()));
8930fca6ea1SDimitry Andric emitAlignment(Align(8));
8940fca6ea1SDimitry Andric
8950fca6ea1SDimitry Andric for (const auto &Stub : Stubs)
8960fca6ea1SDimitry Andric emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
8970fca6ea1SDimitry Andric
8980fca6ea1SDimitry Andric OutStreamer->addBlankLine();
8990fca6ea1SDimitry Andric }
9000fca6ea1SDimitry Andric
9010b57cec5SDimitry Andric // Funny Darwin hack: This flag tells the linker that no global symbols
9020b57cec5SDimitry Andric // contain code that falls through to other global symbols (e.g. the obvious
9030b57cec5SDimitry Andric // implementation of multiple entry points). If this doesn't occur, the
9040b57cec5SDimitry Andric // linker can safely perform dead code stripping. Since LLVM never
9050b57cec5SDimitry Andric // generates code that does this, it is always safe to set.
9065ffd83dbSDimitry Andric OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols);
9070b57cec5SDimitry Andric }
908e8d8bef9SDimitry Andric
9090fca6ea1SDimitry Andric if (TT.isOSBinFormatELF()) {
9100fca6ea1SDimitry Andric // Output authenticated pointers as indirect symbols, if we have any.
9110fca6ea1SDimitry Andric MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
9120fca6ea1SDimitry Andric
9130fca6ea1SDimitry Andric auto Stubs = MMIELF.getAuthGVStubList();
9140fca6ea1SDimitry Andric
9150fca6ea1SDimitry Andric if (!Stubs.empty()) {
9160fca6ea1SDimitry Andric const TargetLoweringObjectFile &TLOF = getObjFileLowering();
9170fca6ea1SDimitry Andric OutStreamer->switchSection(TLOF.getDataSection());
9180fca6ea1SDimitry Andric emitAlignment(Align(8));
9190fca6ea1SDimitry Andric
9200fca6ea1SDimitry Andric for (const auto &Stub : Stubs)
9210fca6ea1SDimitry Andric emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second);
9220fca6ea1SDimitry Andric
9230fca6ea1SDimitry Andric OutStreamer->addBlankLine();
9240fca6ea1SDimitry Andric }
9250fca6ea1SDimitry Andric }
9260fca6ea1SDimitry Andric
927e8d8bef9SDimitry Andric // Emit stack and fault map information.
928e8d8bef9SDimitry Andric FM.serializeToFaultMapSection();
929e8d8bef9SDimitry Andric
9300b57cec5SDimitry Andric }
9310b57cec5SDimitry Andric
emitLOHs()932fe6060f1SDimitry Andric void AArch64AsmPrinter::emitLOHs() {
9330b57cec5SDimitry Andric SmallVector<MCSymbol *, 3> MCArgs;
9340b57cec5SDimitry Andric
9350b57cec5SDimitry Andric for (const auto &D : AArch64FI->getLOHContainer()) {
9360b57cec5SDimitry Andric for (const MachineInstr *MI : D.getArgs()) {
9370b57cec5SDimitry Andric MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
9380b57cec5SDimitry Andric assert(LabelIt != LOHInstToLabel.end() &&
9390b57cec5SDimitry Andric "Label hasn't been inserted for LOH related instruction");
9400b57cec5SDimitry Andric MCArgs.push_back(LabelIt->second);
9410b57cec5SDimitry Andric }
9425ffd83dbSDimitry Andric OutStreamer->emitLOHDirective(D.getKind(), MCArgs);
9430b57cec5SDimitry Andric MCArgs.clear();
9440b57cec5SDimitry Andric }
9450b57cec5SDimitry Andric }
9460b57cec5SDimitry Andric
emitFunctionBodyEnd()9475ffd83dbSDimitry Andric void AArch64AsmPrinter::emitFunctionBodyEnd() {
9480b57cec5SDimitry Andric if (!AArch64FI->getLOHRelated().empty())
949fe6060f1SDimitry Andric emitLOHs();
9500b57cec5SDimitry Andric }
9510b57cec5SDimitry Andric
9520b57cec5SDimitry Andric /// GetCPISymbol - Return the symbol for the specified constant pool entry.
GetCPISymbol(unsigned CPID) const9530b57cec5SDimitry Andric MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
9540b57cec5SDimitry Andric // Darwin uses a linker-private symbol name for constant-pools (to
9550b57cec5SDimitry Andric // avoid addends on the relocation?), ELF has no such concept and
9560b57cec5SDimitry Andric // uses a normal private symbol.
9570b57cec5SDimitry Andric if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
9580b57cec5SDimitry Andric return OutContext.getOrCreateSymbol(
9590b57cec5SDimitry Andric Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
9600b57cec5SDimitry Andric Twine(getFunctionNumber()) + "_" + Twine(CPID));
9610b57cec5SDimitry Andric
9620b57cec5SDimitry Andric return AsmPrinter::GetCPISymbol(CPID);
9630b57cec5SDimitry Andric }
9640b57cec5SDimitry Andric
printOperand(const MachineInstr * MI,unsigned OpNum,raw_ostream & O)9650b57cec5SDimitry Andric void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
9660b57cec5SDimitry Andric raw_ostream &O) {
9670b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum);
9680b57cec5SDimitry Andric switch (MO.getType()) {
9690b57cec5SDimitry Andric default:
9700b57cec5SDimitry Andric llvm_unreachable("<unknown operand type>");
9710b57cec5SDimitry Andric case MachineOperand::MO_Register: {
9728bcb0991SDimitry Andric Register Reg = MO.getReg();
973bdd1243dSDimitry Andric assert(Reg.isPhysical());
9740b57cec5SDimitry Andric assert(!MO.getSubReg() && "Subregs should be eliminated!");
9750b57cec5SDimitry Andric O << AArch64InstPrinter::getRegisterName(Reg);
9760b57cec5SDimitry Andric break;
9770b57cec5SDimitry Andric }
9780b57cec5SDimitry Andric case MachineOperand::MO_Immediate: {
9798bcb0991SDimitry Andric O << MO.getImm();
9800b57cec5SDimitry Andric break;
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: {
9830b57cec5SDimitry Andric PrintSymbolOperand(MO, O);
9840b57cec5SDimitry Andric break;
9850b57cec5SDimitry Andric }
9860b57cec5SDimitry Andric case MachineOperand::MO_BlockAddress: {
9870b57cec5SDimitry Andric MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
9880b57cec5SDimitry Andric Sym->print(O, MAI);
9890b57cec5SDimitry Andric break;
9900b57cec5SDimitry Andric }
9910b57cec5SDimitry Andric }
9920b57cec5SDimitry Andric }
9930b57cec5SDimitry Andric
printAsmMRegister(const MachineOperand & MO,char Mode,raw_ostream & O)9940b57cec5SDimitry Andric bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
9950b57cec5SDimitry Andric raw_ostream &O) {
9968bcb0991SDimitry Andric Register Reg = MO.getReg();
9970b57cec5SDimitry Andric switch (Mode) {
9980b57cec5SDimitry Andric default:
9990b57cec5SDimitry Andric return true; // Unknown mode.
10000b57cec5SDimitry Andric case 'w':
10010b57cec5SDimitry Andric Reg = getWRegFromXReg(Reg);
10020b57cec5SDimitry Andric break;
10030b57cec5SDimitry Andric case 'x':
10040b57cec5SDimitry Andric Reg = getXRegFromWReg(Reg);
10050b57cec5SDimitry Andric break;
10066e75b2fbSDimitry Andric case 't':
10076e75b2fbSDimitry Andric Reg = getXRegFromXRegTuple(Reg);
10086e75b2fbSDimitry Andric break;
10090b57cec5SDimitry Andric }
10100b57cec5SDimitry Andric
10110b57cec5SDimitry Andric O << AArch64InstPrinter::getRegisterName(Reg);
10120b57cec5SDimitry Andric return false;
10130b57cec5SDimitry Andric }
10140b57cec5SDimitry Andric
10150b57cec5SDimitry Andric // Prints the register in MO using class RC using the offset in the
10160b57cec5SDimitry Andric // new register class. This should not be used for cross class
10170b57cec5SDimitry Andric // printing.
printAsmRegInClass(const MachineOperand & MO,const TargetRegisterClass * RC,unsigned AltName,raw_ostream & O)10180b57cec5SDimitry Andric bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
10190b57cec5SDimitry Andric const TargetRegisterClass *RC,
10208bcb0991SDimitry Andric unsigned AltName, raw_ostream &O) {
10210b57cec5SDimitry Andric assert(MO.isReg() && "Should only get here with a register!");
10220b57cec5SDimitry Andric const TargetRegisterInfo *RI = STI->getRegisterInfo();
10238bcb0991SDimitry Andric Register Reg = MO.getReg();
10240b57cec5SDimitry Andric unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
1025e8d8bef9SDimitry Andric if (!RI->regsOverlap(RegToPrint, Reg))
1026e8d8bef9SDimitry Andric return true;
10278bcb0991SDimitry Andric O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName);
10280b57cec5SDimitry Andric return false;
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric
PrintAsmOperand(const MachineInstr * MI,unsigned OpNum,const char * ExtraCode,raw_ostream & O)10310b57cec5SDimitry Andric bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
10320b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) {
10330b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum);
10340b57cec5SDimitry Andric
10350b57cec5SDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'.
10360b57cec5SDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
10370b57cec5SDimitry Andric return false;
10380b57cec5SDimitry Andric
10390b57cec5SDimitry Andric // Does this asm operand have a single letter operand modifier?
10400b57cec5SDimitry Andric if (ExtraCode && ExtraCode[0]) {
10410b57cec5SDimitry Andric if (ExtraCode[1] != 0)
10420b57cec5SDimitry Andric return true; // Unknown modifier.
10430b57cec5SDimitry Andric
10440b57cec5SDimitry Andric switch (ExtraCode[0]) {
10450b57cec5SDimitry Andric default:
10460b57cec5SDimitry Andric return true; // Unknown modifier.
10470b57cec5SDimitry Andric case 'w': // Print W register
10480b57cec5SDimitry Andric case 'x': // Print X register
10490b57cec5SDimitry Andric if (MO.isReg())
10500b57cec5SDimitry Andric return printAsmMRegister(MO, ExtraCode[0], O);
10510b57cec5SDimitry Andric if (MO.isImm() && MO.getImm() == 0) {
10520b57cec5SDimitry Andric unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
10530b57cec5SDimitry Andric O << AArch64InstPrinter::getRegisterName(Reg);
10540b57cec5SDimitry Andric return false;
10550b57cec5SDimitry Andric }
10560b57cec5SDimitry Andric printOperand(MI, OpNum, O);
10570b57cec5SDimitry Andric return false;
10580b57cec5SDimitry Andric case 'b': // Print B register.
10590b57cec5SDimitry Andric case 'h': // Print H register.
10600b57cec5SDimitry Andric case 's': // Print S register.
10610b57cec5SDimitry Andric case 'd': // Print D register.
10620b57cec5SDimitry Andric case 'q': // Print Q register.
10638bcb0991SDimitry Andric case 'z': // Print Z register.
10640b57cec5SDimitry Andric if (MO.isReg()) {
10650b57cec5SDimitry Andric const TargetRegisterClass *RC;
10660b57cec5SDimitry Andric switch (ExtraCode[0]) {
10670b57cec5SDimitry Andric case 'b':
10680b57cec5SDimitry Andric RC = &AArch64::FPR8RegClass;
10690b57cec5SDimitry Andric break;
10700b57cec5SDimitry Andric case 'h':
10710b57cec5SDimitry Andric RC = &AArch64::FPR16RegClass;
10720b57cec5SDimitry Andric break;
10730b57cec5SDimitry Andric case 's':
10740b57cec5SDimitry Andric RC = &AArch64::FPR32RegClass;
10750b57cec5SDimitry Andric break;
10760b57cec5SDimitry Andric case 'd':
10770b57cec5SDimitry Andric RC = &AArch64::FPR64RegClass;
10780b57cec5SDimitry Andric break;
10790b57cec5SDimitry Andric case 'q':
10800b57cec5SDimitry Andric RC = &AArch64::FPR128RegClass;
10810b57cec5SDimitry Andric break;
10828bcb0991SDimitry Andric case 'z':
10838bcb0991SDimitry Andric RC = &AArch64::ZPRRegClass;
10848bcb0991SDimitry Andric break;
10850b57cec5SDimitry Andric default:
10860b57cec5SDimitry Andric return true;
10870b57cec5SDimitry Andric }
10888bcb0991SDimitry Andric return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
10890b57cec5SDimitry Andric }
10900b57cec5SDimitry Andric printOperand(MI, OpNum, O);
10910b57cec5SDimitry Andric return false;
10920b57cec5SDimitry Andric }
10930b57cec5SDimitry Andric }
10940b57cec5SDimitry Andric
10950b57cec5SDimitry Andric // According to ARM, we should emit x and v registers unless we have a
10960b57cec5SDimitry Andric // modifier.
10970b57cec5SDimitry Andric if (MO.isReg()) {
10988bcb0991SDimitry Andric Register Reg = MO.getReg();
10990b57cec5SDimitry Andric
11000b57cec5SDimitry Andric // If this is a w or x register, print an x register.
11010b57cec5SDimitry Andric if (AArch64::GPR32allRegClass.contains(Reg) ||
11020b57cec5SDimitry Andric AArch64::GPR64allRegClass.contains(Reg))
11030b57cec5SDimitry Andric return printAsmMRegister(MO, 'x', O);
11040b57cec5SDimitry Andric
11056e75b2fbSDimitry Andric // If this is an x register tuple, print an x register.
11066e75b2fbSDimitry Andric if (AArch64::GPR64x8ClassRegClass.contains(Reg))
11076e75b2fbSDimitry Andric return printAsmMRegister(MO, 't', O);
11086e75b2fbSDimitry Andric
11098bcb0991SDimitry Andric unsigned AltName = AArch64::NoRegAltName;
11108bcb0991SDimitry Andric const TargetRegisterClass *RegClass;
11118bcb0991SDimitry Andric if (AArch64::ZPRRegClass.contains(Reg)) {
11128bcb0991SDimitry Andric RegClass = &AArch64::ZPRRegClass;
11138bcb0991SDimitry Andric } else if (AArch64::PPRRegClass.contains(Reg)) {
11148bcb0991SDimitry Andric RegClass = &AArch64::PPRRegClass;
11155f757f3fSDimitry Andric } else if (AArch64::PNRRegClass.contains(Reg)) {
11165f757f3fSDimitry Andric RegClass = &AArch64::PNRRegClass;
11178bcb0991SDimitry Andric } else {
11188bcb0991SDimitry Andric RegClass = &AArch64::FPR128RegClass;
11198bcb0991SDimitry Andric AltName = AArch64::vreg;
11208bcb0991SDimitry Andric }
11218bcb0991SDimitry Andric
11220b57cec5SDimitry Andric // If this is a b, h, s, d, or q register, print it as a v register.
11238bcb0991SDimitry Andric return printAsmRegInClass(MO, RegClass, AltName, O);
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric
11260b57cec5SDimitry Andric printOperand(MI, OpNum, O);
11270b57cec5SDimitry Andric return false;
11280b57cec5SDimitry Andric }
11290b57cec5SDimitry Andric
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNum,const char * ExtraCode,raw_ostream & O)11300b57cec5SDimitry Andric bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
11310b57cec5SDimitry Andric unsigned OpNum,
11320b57cec5SDimitry Andric const char *ExtraCode,
11330b57cec5SDimitry Andric raw_ostream &O) {
11340b57cec5SDimitry Andric if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
11350b57cec5SDimitry Andric return true; // Unknown modifier.
11360b57cec5SDimitry Andric
11370b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum);
11380b57cec5SDimitry Andric assert(MO.isReg() && "unexpected inline asm memory operand");
11390b57cec5SDimitry Andric O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
11400b57cec5SDimitry Andric return false;
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric
PrintDebugValueComment(const MachineInstr * MI,raw_ostream & OS)11430b57cec5SDimitry Andric void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
11440b57cec5SDimitry Andric raw_ostream &OS) {
11450b57cec5SDimitry Andric unsigned NOps = MI->getNumOperands();
11460b57cec5SDimitry Andric assert(NOps == 4);
11470b57cec5SDimitry Andric OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
11480b57cec5SDimitry Andric // cast away const; DIetc do not take const operands for some reason.
11495ffd83dbSDimitry Andric OS << MI->getDebugVariable()->getName();
11500b57cec5SDimitry Andric OS << " <- ";
11510b57cec5SDimitry Andric // Frame address. Currently handles register +- offset only.
1152fe6060f1SDimitry Andric assert(MI->isIndirectDebugValue());
11530b57cec5SDimitry Andric OS << '[';
1154fe6060f1SDimitry Andric for (unsigned I = 0, E = std::distance(MI->debug_operands().begin(),
1155fe6060f1SDimitry Andric MI->debug_operands().end());
1156fe6060f1SDimitry Andric I < E; ++I) {
1157fe6060f1SDimitry Andric if (I != 0)
1158fe6060f1SDimitry Andric OS << ", ";
1159fe6060f1SDimitry Andric printOperand(MI, I, OS);
1160fe6060f1SDimitry Andric }
11610b57cec5SDimitry Andric OS << ']';
11620b57cec5SDimitry Andric OS << "+";
11630b57cec5SDimitry Andric printOperand(MI, NOps - 2, OS);
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric
emitJumpTableInfo()11665ffd83dbSDimitry Andric void AArch64AsmPrinter::emitJumpTableInfo() {
11670b57cec5SDimitry Andric const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
11680b57cec5SDimitry Andric if (!MJTI) return;
11690b57cec5SDimitry Andric
11700b57cec5SDimitry Andric const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
11710b57cec5SDimitry Andric if (JT.empty()) return;
11720b57cec5SDimitry Andric
11730b57cec5SDimitry Andric const TargetLoweringObjectFile &TLOF = getObjFileLowering();
11744824e7fdSDimitry Andric MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(MF->getFunction(), TM);
117581ad6265SDimitry Andric OutStreamer->switchSection(ReadOnlySec);
11760b57cec5SDimitry Andric
11770b57cec5SDimitry Andric auto AFI = MF->getInfo<AArch64FunctionInfo>();
11780b57cec5SDimitry Andric for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
11790b57cec5SDimitry Andric const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
11800b57cec5SDimitry Andric
11810b57cec5SDimitry Andric // If this jump table was deleted, ignore it.
11820b57cec5SDimitry Andric if (JTBBs.empty()) continue;
11830b57cec5SDimitry Andric
11840b57cec5SDimitry Andric unsigned Size = AFI->getJumpTableEntrySize(JTI);
11855ffd83dbSDimitry Andric emitAlignment(Align(Size));
11865ffd83dbSDimitry Andric OutStreamer->emitLabel(GetJTISymbol(JTI));
11870b57cec5SDimitry Andric
1188e8d8bef9SDimitry Andric const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
11890b57cec5SDimitry Andric const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
1190e8d8bef9SDimitry Andric
1191e8d8bef9SDimitry Andric for (auto *JTBB : JTBBs) {
1192e8d8bef9SDimitry Andric const MCExpr *Value =
1193e8d8bef9SDimitry Andric MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext);
1194e8d8bef9SDimitry Andric
1195e8d8bef9SDimitry Andric // Each entry is:
1196e8d8bef9SDimitry Andric // .byte/.hword (LBB - Lbase)>>2
1197e8d8bef9SDimitry Andric // or plain:
1198e8d8bef9SDimitry Andric // .word LBB - Lbase
11990b57cec5SDimitry Andric Value = MCBinaryExpr::createSub(Value, Base, OutContext);
1200e8d8bef9SDimitry Andric if (Size != 4)
12010b57cec5SDimitry Andric Value = MCBinaryExpr::createLShr(
12020b57cec5SDimitry Andric Value, MCConstantExpr::create(2, OutContext), OutContext);
12030b57cec5SDimitry Andric
12045ffd83dbSDimitry Andric OutStreamer->emitValue(Value, Size);
12050b57cec5SDimitry Andric }
1206e8d8bef9SDimitry Andric }
1207e8d8bef9SDimitry Andric }
12080b57cec5SDimitry Andric
12095f757f3fSDimitry Andric std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
12105f757f3fSDimitry Andric codeview::JumpTableEntrySize>
getCodeViewJumpTableInfo(int JTI,const MachineInstr * BranchInstr,const MCSymbol * BranchLabel) const12115f757f3fSDimitry Andric AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI,
12125f757f3fSDimitry Andric const MachineInstr *BranchInstr,
12135f757f3fSDimitry Andric const MCSymbol *BranchLabel) const {
12145f757f3fSDimitry Andric const auto AFI = MF->getInfo<AArch64FunctionInfo>();
12155f757f3fSDimitry Andric const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
12165f757f3fSDimitry Andric codeview::JumpTableEntrySize EntrySize;
12175f757f3fSDimitry Andric switch (AFI->getJumpTableEntrySize(JTI)) {
12185f757f3fSDimitry Andric case 1:
12195f757f3fSDimitry Andric EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
12205f757f3fSDimitry Andric break;
12215f757f3fSDimitry Andric case 2:
12225f757f3fSDimitry Andric EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
12235f757f3fSDimitry Andric break;
12245f757f3fSDimitry Andric case 4:
12255f757f3fSDimitry Andric EntrySize = codeview::JumpTableEntrySize::Int32;
12265f757f3fSDimitry Andric break;
12275f757f3fSDimitry Andric default:
12285f757f3fSDimitry Andric llvm_unreachable("Unexpected jump table entry size");
12295f757f3fSDimitry Andric }
12305f757f3fSDimitry Andric return std::make_tuple(Base, 0, BranchLabel, EntrySize);
12315f757f3fSDimitry Andric }
12325f757f3fSDimitry Andric
emitFunctionEntryLabel()1233eaeb601bSDimitry Andric void AArch64AsmPrinter::emitFunctionEntryLabel() {
1234eaeb601bSDimitry Andric if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
1235eaeb601bSDimitry Andric MF->getFunction().getCallingConv() ==
1236eaeb601bSDimitry Andric CallingConv::AArch64_SVE_VectorCall ||
123781ad6265SDimitry Andric MF->getInfo<AArch64FunctionInfo>()->isSVECC()) {
1238eaeb601bSDimitry Andric auto *TS =
1239eaeb601bSDimitry Andric static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
1240eaeb601bSDimitry Andric TS->emitDirectiveVariantPCS(CurrentFnSym);
1241eaeb601bSDimitry Andric }
1242eaeb601bSDimitry Andric
12437a6dacacSDimitry Andric AsmPrinter::emitFunctionEntryLabel();
12447a6dacacSDimitry Andric
12450fca6ea1SDimitry Andric if (TM.getTargetTriple().isWindowsArm64EC() &&
12460fca6ea1SDimitry Andric !MF->getFunction().hasLocalLinkage()) {
12470fca6ea1SDimitry Andric // For ARM64EC targets, a function definition's name is mangled differently
12480fca6ea1SDimitry Andric // from the normal symbol, emit required aliases here.
12490fca6ea1SDimitry Andric auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) {
12500fca6ea1SDimitry Andric OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep);
12517a6dacacSDimitry Andric OutStreamer->emitAssignment(
12520fca6ea1SDimitry Andric Src, MCSymbolRefExpr::create(Dst, MCSymbolRefExpr::VK_None,
12537a6dacacSDimitry Andric MMI->getContext()));
12540fca6ea1SDimitry Andric };
12550fca6ea1SDimitry Andric
12560fca6ea1SDimitry Andric auto getSymbolFromMetadata = [&](StringRef Name) {
12570fca6ea1SDimitry Andric MCSymbol *Sym = nullptr;
12580fca6ea1SDimitry Andric if (MDNode *Node = MF->getFunction().getMetadata(Name)) {
12590fca6ea1SDimitry Andric StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString();
12600fca6ea1SDimitry Andric Sym = MMI->getContext().getOrCreateSymbol(NameStr);
12610fca6ea1SDimitry Andric }
12620fca6ea1SDimitry Andric return Sym;
12630fca6ea1SDimitry Andric };
12640fca6ea1SDimitry Andric
12650fca6ea1SDimitry Andric if (MCSymbol *UnmangledSym =
12660fca6ea1SDimitry Andric getSymbolFromMetadata("arm64ec_unmangled_name")) {
12670fca6ea1SDimitry Andric MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name");
12680fca6ea1SDimitry Andric
12690fca6ea1SDimitry Andric if (ECMangledSym) {
12700fca6ea1SDimitry Andric // An external function, emit the alias from the unmangled symbol to
12710fca6ea1SDimitry Andric // mangled symbol name and the alias from the mangled symbol to guest
12720fca6ea1SDimitry Andric // exit thunk.
12730fca6ea1SDimitry Andric emitFunctionAlias(UnmangledSym, ECMangledSym);
12740fca6ea1SDimitry Andric emitFunctionAlias(ECMangledSym, CurrentFnSym);
12757a6dacacSDimitry Andric } else {
12760fca6ea1SDimitry Andric // A function implementation, emit the alias from the unmangled symbol
12770fca6ea1SDimitry Andric // to mangled symbol name.
12780fca6ea1SDimitry Andric emitFunctionAlias(UnmangledSym, CurrentFnSym);
12790fca6ea1SDimitry Andric }
12807a6dacacSDimitry Andric }
12817a6dacacSDimitry Andric }
12827a6dacacSDimitry Andric }
12837a6dacacSDimitry Andric
emitGlobalAlias(const Module & M,const GlobalAlias & GA)12840fca6ea1SDimitry Andric void AArch64AsmPrinter::emitGlobalAlias(const Module &M,
12850fca6ea1SDimitry Andric const GlobalAlias &GA) {
12860fca6ea1SDimitry Andric if (auto F = dyn_cast_or_null<Function>(GA.getAliasee())) {
12870fca6ea1SDimitry Andric // Global aliases must point to a definition, but unmangled patchable
12880fca6ea1SDimitry Andric // symbols are special and need to point to an undefined symbol with "EXP+"
12890fca6ea1SDimitry Andric // prefix. Such undefined symbol is resolved by the linker by creating
12900fca6ea1SDimitry Andric // x86 thunk that jumps back to the actual EC target.
12910fca6ea1SDimitry Andric if (MDNode *Node = F->getMetadata("arm64ec_exp_name")) {
12920fca6ea1SDimitry Andric StringRef ExpStr = cast<MDString>(Node->getOperand(0))->getString();
12930fca6ea1SDimitry Andric MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr);
12940fca6ea1SDimitry Andric MCSymbol *Sym = MMI->getContext().getOrCreateSymbol(GA.getName());
1295*62987288SDimitry Andric
1296*62987288SDimitry Andric OutStreamer->beginCOFFSymbolDef(ExpSym);
1297*62987288SDimitry Andric OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
1298*62987288SDimitry Andric OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
1299*62987288SDimitry Andric << COFF::SCT_COMPLEX_TYPE_SHIFT);
1300*62987288SDimitry Andric OutStreamer->endCOFFSymbolDef();
1301*62987288SDimitry Andric
13020fca6ea1SDimitry Andric OutStreamer->beginCOFFSymbolDef(Sym);
13030fca6ea1SDimitry Andric OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
13040fca6ea1SDimitry Andric OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
13050fca6ea1SDimitry Andric << COFF::SCT_COMPLEX_TYPE_SHIFT);
13060fca6ea1SDimitry Andric OutStreamer->endCOFFSymbolDef();
13070fca6ea1SDimitry Andric OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
13080fca6ea1SDimitry Andric OutStreamer->emitAssignment(
13090fca6ea1SDimitry Andric Sym, MCSymbolRefExpr::create(ExpSym, MCSymbolRefExpr::VK_None,
13100fca6ea1SDimitry Andric MMI->getContext()));
13110fca6ea1SDimitry Andric return;
13120fca6ea1SDimitry Andric }
13130fca6ea1SDimitry Andric }
13140fca6ea1SDimitry Andric AsmPrinter::emitGlobalAlias(M, GA);
1315eaeb601bSDimitry Andric }
1316eaeb601bSDimitry Andric
13170b57cec5SDimitry Andric /// Small jump tables contain an unsigned byte or half, representing the offset
13180b57cec5SDimitry Andric /// from the lowest-addressed possible destination to the desired basic
13190b57cec5SDimitry Andric /// block. Since all instructions are 4-byte aligned, this is further compressed
13200b57cec5SDimitry Andric /// by counting in instructions rather than bytes (i.e. divided by 4). So, to
13210b57cec5SDimitry Andric /// materialize the correct destination we need:
13220b57cec5SDimitry Andric ///
13230b57cec5SDimitry Andric /// adr xDest, .LBB0_0
13240b57cec5SDimitry Andric /// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
1325e8d8bef9SDimitry Andric /// add xDest, xDest, xScratch (with "lsl #2" for smaller entries)
LowerJumpTableDest(llvm::MCStreamer & OutStreamer,const llvm::MachineInstr & MI)1326e8d8bef9SDimitry Andric void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer,
13270b57cec5SDimitry Andric const llvm::MachineInstr &MI) {
13288bcb0991SDimitry Andric Register DestReg = MI.getOperand(0).getReg();
13298bcb0991SDimitry Andric Register ScratchReg = MI.getOperand(1).getReg();
13308bcb0991SDimitry Andric Register ScratchRegW =
13310b57cec5SDimitry Andric STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
13328bcb0991SDimitry Andric Register TableReg = MI.getOperand(2).getReg();
13338bcb0991SDimitry Andric Register EntryReg = MI.getOperand(3).getReg();
13340b57cec5SDimitry Andric int JTIdx = MI.getOperand(4).getIndex();
1335e8d8bef9SDimitry Andric int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
13360b57cec5SDimitry Andric
13370b57cec5SDimitry Andric // This has to be first because the compression pass based its reachability
13380b57cec5SDimitry Andric // calculations on the start of the JumpTableDest instruction.
13390b57cec5SDimitry Andric auto Label =
13400b57cec5SDimitry Andric MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
1341e8d8bef9SDimitry Andric
1342e8d8bef9SDimitry Andric // If we don't already have a symbol to use as the base, use the ADR
1343e8d8bef9SDimitry Andric // instruction itself.
1344e8d8bef9SDimitry Andric if (!Label) {
1345e8d8bef9SDimitry Andric Label = MF->getContext().createTempSymbol();
1346e8d8bef9SDimitry Andric AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label);
1347e8d8bef9SDimitry Andric OutStreamer.emitLabel(Label);
1348e8d8bef9SDimitry Andric }
1349e8d8bef9SDimitry Andric
1350e8d8bef9SDimitry Andric auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext());
13510b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
13520b57cec5SDimitry Andric .addReg(DestReg)
1353e8d8bef9SDimitry Andric .addExpr(LabelExpr));
13540b57cec5SDimitry Andric
13550b57cec5SDimitry Andric // Load the number of instruction-steps to offset from the label.
1356e8d8bef9SDimitry Andric unsigned LdrOpcode;
1357e8d8bef9SDimitry Andric switch (Size) {
1358e8d8bef9SDimitry Andric case 1: LdrOpcode = AArch64::LDRBBroX; break;
1359e8d8bef9SDimitry Andric case 2: LdrOpcode = AArch64::LDRHHroX; break;
1360e8d8bef9SDimitry Andric case 4: LdrOpcode = AArch64::LDRSWroX; break;
1361e8d8bef9SDimitry Andric default:
1362e8d8bef9SDimitry Andric llvm_unreachable("Unknown jump table size");
1363e8d8bef9SDimitry Andric }
1364e8d8bef9SDimitry Andric
13650b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
1366e8d8bef9SDimitry Andric .addReg(Size == 4 ? ScratchReg : ScratchRegW)
13670b57cec5SDimitry Andric .addReg(TableReg)
13680b57cec5SDimitry Andric .addReg(EntryReg)
13690b57cec5SDimitry Andric .addImm(0)
1370e8d8bef9SDimitry Andric .addImm(Size == 1 ? 0 : 1));
13710b57cec5SDimitry Andric
1372e8d8bef9SDimitry Andric // Add to the already materialized base label address, multiplying by 4 if
1373e8d8bef9SDimitry Andric // compressed.
13740b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
13750b57cec5SDimitry Andric .addReg(DestReg)
13760b57cec5SDimitry Andric .addReg(DestReg)
13770b57cec5SDimitry Andric .addReg(ScratchReg)
1378e8d8bef9SDimitry Andric .addImm(Size == 4 ? 0 : 2));
13790b57cec5SDimitry Andric }
13800b57cec5SDimitry Andric
LowerHardenedBRJumpTable(const MachineInstr & MI)13810fca6ea1SDimitry Andric void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) {
13820fca6ea1SDimitry Andric unsigned InstsEmitted = 0;
13830fca6ea1SDimitry Andric
13840fca6ea1SDimitry Andric const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
13850fca6ea1SDimitry Andric assert(MJTI && "Can't lower jump-table dispatch without JTI");
13860fca6ea1SDimitry Andric
13870fca6ea1SDimitry Andric const std::vector<MachineJumpTableEntry> &JTs = MJTI->getJumpTables();
13880fca6ea1SDimitry Andric assert(!JTs.empty() && "Invalid JT index for jump-table dispatch");
13890fca6ea1SDimitry Andric
13900fca6ea1SDimitry Andric // Emit:
13910fca6ea1SDimitry Andric // mov x17, #<size of table> ; depending on table size, with MOVKs
13920fca6ea1SDimitry Andric // cmp x16, x17 ; or #imm if table size fits in 12-bit
13930fca6ea1SDimitry Andric // csel x16, x16, xzr, ls ; check for index overflow
13940fca6ea1SDimitry Andric //
13950fca6ea1SDimitry Andric // adrp x17, Ltable@PAGE ; materialize table address
13960fca6ea1SDimitry Andric // add x17, Ltable@PAGEOFF
13970fca6ea1SDimitry Andric // ldrsw x16, [x17, x16, lsl #2] ; load table entry
13980fca6ea1SDimitry Andric //
13990fca6ea1SDimitry Andric // Lanchor:
14000fca6ea1SDimitry Andric // adr x17, Lanchor ; compute target address
14010fca6ea1SDimitry Andric // add x16, x17, x16
14020fca6ea1SDimitry Andric // br x16 ; branch to target
14030fca6ea1SDimitry Andric
14040fca6ea1SDimitry Andric MachineOperand JTOp = MI.getOperand(0);
14050fca6ea1SDimitry Andric
14060fca6ea1SDimitry Andric unsigned JTI = JTOp.getIndex();
14070fca6ea1SDimitry Andric assert(!AArch64FI->getJumpTableEntryPCRelSymbol(JTI) &&
14080fca6ea1SDimitry Andric "unsupported compressed jump table");
14090fca6ea1SDimitry Andric
14100fca6ea1SDimitry Andric const uint64_t NumTableEntries = JTs[JTI].MBBs.size();
14110fca6ea1SDimitry Andric
14120fca6ea1SDimitry Andric // cmp only supports a 12-bit immediate. If we need more, materialize the
14130fca6ea1SDimitry Andric // immediate, using x17 as a scratch register.
14140fca6ea1SDimitry Andric uint64_t MaxTableEntry = NumTableEntries - 1;
14150fca6ea1SDimitry Andric if (isUInt<12>(MaxTableEntry)) {
14160fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXri)
14170fca6ea1SDimitry Andric .addReg(AArch64::XZR)
14180fca6ea1SDimitry Andric .addReg(AArch64::X16)
14190fca6ea1SDimitry Andric .addImm(MaxTableEntry)
14200fca6ea1SDimitry Andric .addImm(0));
14210fca6ea1SDimitry Andric ++InstsEmitted;
14220fca6ea1SDimitry Andric } else {
14230fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer,
14240fca6ea1SDimitry Andric MCInstBuilder(AArch64::MOVZXi)
14250fca6ea1SDimitry Andric .addReg(AArch64::X17)
14260fca6ea1SDimitry Andric .addImm(static_cast<uint16_t>(MaxTableEntry))
14270fca6ea1SDimitry Andric .addImm(0));
14280fca6ea1SDimitry Andric ++InstsEmitted;
14290fca6ea1SDimitry Andric // It's sad that we have to manually materialize instructions, but we can't
14300fca6ea1SDimitry Andric // trivially reuse the main pseudo expansion logic.
14310fca6ea1SDimitry Andric // A MOVK sequence is easy enough to generate and handles the general case.
14320fca6ea1SDimitry Andric for (int Offset = 16; Offset < 64; Offset += 16) {
14330fca6ea1SDimitry Andric if ((MaxTableEntry >> Offset) == 0)
14340fca6ea1SDimitry Andric break;
14350fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer,
14360fca6ea1SDimitry Andric MCInstBuilder(AArch64::MOVKXi)
14370fca6ea1SDimitry Andric .addReg(AArch64::X17)
14380fca6ea1SDimitry Andric .addReg(AArch64::X17)
14390fca6ea1SDimitry Andric .addImm(static_cast<uint16_t>(MaxTableEntry >> Offset))
14400fca6ea1SDimitry Andric .addImm(Offset));
14410fca6ea1SDimitry Andric ++InstsEmitted;
14420fca6ea1SDimitry Andric }
14430fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs)
14440fca6ea1SDimitry Andric .addReg(AArch64::XZR)
14450fca6ea1SDimitry Andric .addReg(AArch64::X16)
14460fca6ea1SDimitry Andric .addReg(AArch64::X17)
14470fca6ea1SDimitry Andric .addImm(0));
14480fca6ea1SDimitry Andric ++InstsEmitted;
14490fca6ea1SDimitry Andric }
14500fca6ea1SDimitry Andric
14510fca6ea1SDimitry Andric // This picks entry #0 on failure.
14520fca6ea1SDimitry Andric // We might want to trap instead.
14530fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CSELXr)
14540fca6ea1SDimitry Andric .addReg(AArch64::X16)
14550fca6ea1SDimitry Andric .addReg(AArch64::X16)
14560fca6ea1SDimitry Andric .addReg(AArch64::XZR)
14570fca6ea1SDimitry Andric .addImm(AArch64CC::LS));
14580fca6ea1SDimitry Andric ++InstsEmitted;
14590fca6ea1SDimitry Andric
14600fca6ea1SDimitry Andric // Prepare the @PAGE/@PAGEOFF low/high operands.
14610fca6ea1SDimitry Andric MachineOperand JTMOHi(JTOp), JTMOLo(JTOp);
14620fca6ea1SDimitry Andric MCOperand JTMCHi, JTMCLo;
14630fca6ea1SDimitry Andric
14640fca6ea1SDimitry Andric JTMOHi.setTargetFlags(AArch64II::MO_PAGE);
14650fca6ea1SDimitry Andric JTMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
14660fca6ea1SDimitry Andric
14670fca6ea1SDimitry Andric MCInstLowering.lowerOperand(JTMOHi, JTMCHi);
14680fca6ea1SDimitry Andric MCInstLowering.lowerOperand(JTMOLo, JTMCLo);
14690fca6ea1SDimitry Andric
14700fca6ea1SDimitry Andric EmitToStreamer(
14710fca6ea1SDimitry Andric *OutStreamer,
14720fca6ea1SDimitry Andric MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(JTMCHi));
14730fca6ea1SDimitry Andric ++InstsEmitted;
14740fca6ea1SDimitry Andric
14750fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri)
14760fca6ea1SDimitry Andric .addReg(AArch64::X17)
14770fca6ea1SDimitry Andric .addReg(AArch64::X17)
14780fca6ea1SDimitry Andric .addOperand(JTMCLo)
14790fca6ea1SDimitry Andric .addImm(0));
14800fca6ea1SDimitry Andric ++InstsEmitted;
14810fca6ea1SDimitry Andric
14820fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX)
14830fca6ea1SDimitry Andric .addReg(AArch64::X16)
14840fca6ea1SDimitry Andric .addReg(AArch64::X17)
14850fca6ea1SDimitry Andric .addReg(AArch64::X16)
14860fca6ea1SDimitry Andric .addImm(0)
14870fca6ea1SDimitry Andric .addImm(1));
14880fca6ea1SDimitry Andric ++InstsEmitted;
14890fca6ea1SDimitry Andric
14900fca6ea1SDimitry Andric MCSymbol *AdrLabel = MF->getContext().createTempSymbol();
14910fca6ea1SDimitry Andric const auto *AdrLabelE = MCSymbolRefExpr::create(AdrLabel, MF->getContext());
14920fca6ea1SDimitry Andric AArch64FI->setJumpTableEntryInfo(JTI, 4, AdrLabel);
14930fca6ea1SDimitry Andric
14940fca6ea1SDimitry Andric OutStreamer->emitLabel(AdrLabel);
14950fca6ea1SDimitry Andric EmitToStreamer(
14960fca6ea1SDimitry Andric *OutStreamer,
14970fca6ea1SDimitry Andric MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addExpr(AdrLabelE));
14980fca6ea1SDimitry Andric ++InstsEmitted;
14990fca6ea1SDimitry Andric
15000fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
15010fca6ea1SDimitry Andric .addReg(AArch64::X16)
15020fca6ea1SDimitry Andric .addReg(AArch64::X17)
15030fca6ea1SDimitry Andric .addReg(AArch64::X16)
15040fca6ea1SDimitry Andric .addImm(0));
15050fca6ea1SDimitry Andric ++InstsEmitted;
15060fca6ea1SDimitry Andric
15070fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
15080fca6ea1SDimitry Andric ++InstsEmitted;
15090fca6ea1SDimitry Andric
15100fca6ea1SDimitry Andric (void)InstsEmitted;
15110fca6ea1SDimitry Andric assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4);
15120fca6ea1SDimitry Andric }
15130fca6ea1SDimitry Andric
LowerMOPS(llvm::MCStreamer & OutStreamer,const llvm::MachineInstr & MI)15141fd87a68SDimitry Andric void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer,
15151fd87a68SDimitry Andric const llvm::MachineInstr &MI) {
15161fd87a68SDimitry Andric unsigned Opcode = MI.getOpcode();
15171fd87a68SDimitry Andric assert(STI->hasMOPS());
15181fd87a68SDimitry Andric assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
15191fd87a68SDimitry Andric
15201fd87a68SDimitry Andric const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
15211fd87a68SDimitry Andric if (Opcode == AArch64::MOPSMemoryCopyPseudo)
15221fd87a68SDimitry Andric return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
15231fd87a68SDimitry Andric if (Opcode == AArch64::MOPSMemoryMovePseudo)
15241fd87a68SDimitry Andric return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
15251fd87a68SDimitry Andric if (Opcode == AArch64::MOPSMemorySetPseudo)
15261fd87a68SDimitry Andric return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
15271fd87a68SDimitry Andric if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
15281fd87a68SDimitry Andric return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
15291fd87a68SDimitry Andric llvm_unreachable("Unhandled memory operation pseudo");
15301fd87a68SDimitry Andric }();
15311fd87a68SDimitry Andric const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
15321fd87a68SDimitry Andric Opcode == AArch64::MOPSMemorySetTaggingPseudo;
15331fd87a68SDimitry Andric
15341fd87a68SDimitry Andric for (auto Op : Ops) {
15351fd87a68SDimitry Andric int i = 0;
15361fd87a68SDimitry Andric auto MCIB = MCInstBuilder(Op);
15371fd87a68SDimitry Andric // Destination registers
15381fd87a68SDimitry Andric MCIB.addReg(MI.getOperand(i++).getReg());
15391fd87a68SDimitry Andric MCIB.addReg(MI.getOperand(i++).getReg());
15401fd87a68SDimitry Andric if (!IsSet)
15411fd87a68SDimitry Andric MCIB.addReg(MI.getOperand(i++).getReg());
15421fd87a68SDimitry Andric // Input registers
15431fd87a68SDimitry Andric MCIB.addReg(MI.getOperand(i++).getReg());
15441fd87a68SDimitry Andric MCIB.addReg(MI.getOperand(i++).getReg());
15451fd87a68SDimitry Andric MCIB.addReg(MI.getOperand(i++).getReg());
15461fd87a68SDimitry Andric
15471fd87a68SDimitry Andric EmitToStreamer(OutStreamer, MCIB);
15481fd87a68SDimitry Andric }
15491fd87a68SDimitry Andric }
15501fd87a68SDimitry Andric
LowerSTACKMAP(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)15510b57cec5SDimitry Andric void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
15520b57cec5SDimitry Andric const MachineInstr &MI) {
15530b57cec5SDimitry Andric unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
15540b57cec5SDimitry Andric
1555480093f4SDimitry Andric auto &Ctx = OutStreamer.getContext();
1556480093f4SDimitry Andric MCSymbol *MILabel = Ctx.createTempSymbol();
15575ffd83dbSDimitry Andric OutStreamer.emitLabel(MILabel);
1558480093f4SDimitry Andric
1559480093f4SDimitry Andric SM.recordStackMap(*MILabel, MI);
15600b57cec5SDimitry Andric assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
15610b57cec5SDimitry Andric
15620b57cec5SDimitry Andric // Scan ahead to trim the shadow.
15630b57cec5SDimitry Andric const MachineBasicBlock &MBB = *MI.getParent();
15640b57cec5SDimitry Andric MachineBasicBlock::const_iterator MII(MI);
15650b57cec5SDimitry Andric ++MII;
15660b57cec5SDimitry Andric while (NumNOPBytes > 0) {
15670b57cec5SDimitry Andric if (MII == MBB.end() || MII->isCall() ||
15680b57cec5SDimitry Andric MII->getOpcode() == AArch64::DBG_VALUE ||
15690b57cec5SDimitry Andric MII->getOpcode() == TargetOpcode::PATCHPOINT ||
15700b57cec5SDimitry Andric MII->getOpcode() == TargetOpcode::STACKMAP)
15710b57cec5SDimitry Andric break;
15720b57cec5SDimitry Andric ++MII;
15730b57cec5SDimitry Andric NumNOPBytes -= 4;
15740b57cec5SDimitry Andric }
15750b57cec5SDimitry Andric
15760b57cec5SDimitry Andric // Emit nops.
15770b57cec5SDimitry Andric for (unsigned i = 0; i < NumNOPBytes; i += 4)
15780b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
15790b57cec5SDimitry Andric }
15800b57cec5SDimitry Andric
15810b57cec5SDimitry Andric // Lower a patchpoint of the form:
15820b57cec5SDimitry Andric // [<def>], <id>, <numBytes>, <target>, <numArgs>
LowerPATCHPOINT(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)15830b57cec5SDimitry Andric void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
15840b57cec5SDimitry Andric const MachineInstr &MI) {
1585480093f4SDimitry Andric auto &Ctx = OutStreamer.getContext();
1586480093f4SDimitry Andric MCSymbol *MILabel = Ctx.createTempSymbol();
15875ffd83dbSDimitry Andric OutStreamer.emitLabel(MILabel);
1588480093f4SDimitry Andric SM.recordPatchPoint(*MILabel, MI);
15890b57cec5SDimitry Andric
15900b57cec5SDimitry Andric PatchPointOpers Opers(&MI);
15910b57cec5SDimitry Andric
15920b57cec5SDimitry Andric int64_t CallTarget = Opers.getCallTarget().getImm();
15930b57cec5SDimitry Andric unsigned EncodedBytes = 0;
15940b57cec5SDimitry Andric if (CallTarget) {
15950b57cec5SDimitry Andric assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
15960b57cec5SDimitry Andric "High 16 bits of call target should be zero.");
15978bcb0991SDimitry Andric Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
15980b57cec5SDimitry Andric EncodedBytes = 16;
15990b57cec5SDimitry Andric // Materialize the jump address:
16000b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
16010b57cec5SDimitry Andric .addReg(ScratchReg)
16020b57cec5SDimitry Andric .addImm((CallTarget >> 32) & 0xFFFF)
16030b57cec5SDimitry Andric .addImm(32));
16040b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
16050b57cec5SDimitry Andric .addReg(ScratchReg)
16060b57cec5SDimitry Andric .addReg(ScratchReg)
16070b57cec5SDimitry Andric .addImm((CallTarget >> 16) & 0xFFFF)
16080b57cec5SDimitry Andric .addImm(16));
16090b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
16100b57cec5SDimitry Andric .addReg(ScratchReg)
16110b57cec5SDimitry Andric .addReg(ScratchReg)
16120b57cec5SDimitry Andric .addImm(CallTarget & 0xFFFF)
16130b57cec5SDimitry Andric .addImm(0));
16140b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
16150b57cec5SDimitry Andric }
16160b57cec5SDimitry Andric // Emit padding.
16170b57cec5SDimitry Andric unsigned NumBytes = Opers.getNumPatchBytes();
16180b57cec5SDimitry Andric assert(NumBytes >= EncodedBytes &&
16190b57cec5SDimitry Andric "Patchpoint can't request size less than the length of a call.");
16200b57cec5SDimitry Andric assert((NumBytes - EncodedBytes) % 4 == 0 &&
16210b57cec5SDimitry Andric "Invalid number of NOP bytes requested!");
16220b57cec5SDimitry Andric for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
16230b57cec5SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
16240b57cec5SDimitry Andric }
16250b57cec5SDimitry Andric
LowerSTATEPOINT(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)1626e8d8bef9SDimitry Andric void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1627e8d8bef9SDimitry Andric const MachineInstr &MI) {
1628e8d8bef9SDimitry Andric StatepointOpers SOpers(&MI);
1629e8d8bef9SDimitry Andric if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1630e8d8bef9SDimitry Andric assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
1631e8d8bef9SDimitry Andric for (unsigned i = 0; i < PatchBytes; i += 4)
1632e8d8bef9SDimitry Andric EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
1633e8d8bef9SDimitry Andric } else {
1634e8d8bef9SDimitry Andric // Lower call target and choose correct opcode
1635e8d8bef9SDimitry Andric const MachineOperand &CallTarget = SOpers.getCallTarget();
1636e8d8bef9SDimitry Andric MCOperand CallTargetMCOp;
1637e8d8bef9SDimitry Andric unsigned CallOpcode;
1638e8d8bef9SDimitry Andric switch (CallTarget.getType()) {
1639e8d8bef9SDimitry Andric case MachineOperand::MO_GlobalAddress:
1640e8d8bef9SDimitry Andric case MachineOperand::MO_ExternalSymbol:
1641e8d8bef9SDimitry Andric MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1642e8d8bef9SDimitry Andric CallOpcode = AArch64::BL;
1643e8d8bef9SDimitry Andric break;
1644e8d8bef9SDimitry Andric case MachineOperand::MO_Immediate:
1645e8d8bef9SDimitry Andric CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
1646e8d8bef9SDimitry Andric CallOpcode = AArch64::BL;
1647e8d8bef9SDimitry Andric break;
1648e8d8bef9SDimitry Andric case MachineOperand::MO_Register:
1649e8d8bef9SDimitry Andric CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
1650e8d8bef9SDimitry Andric CallOpcode = AArch64::BLR;
1651e8d8bef9SDimitry Andric break;
1652e8d8bef9SDimitry Andric default:
1653e8d8bef9SDimitry Andric llvm_unreachable("Unsupported operand type in statepoint call target");
1654e8d8bef9SDimitry Andric break;
1655e8d8bef9SDimitry Andric }
1656e8d8bef9SDimitry Andric
1657e8d8bef9SDimitry Andric EmitToStreamer(OutStreamer,
1658e8d8bef9SDimitry Andric MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
1659e8d8bef9SDimitry Andric }
1660e8d8bef9SDimitry Andric
1661e8d8bef9SDimitry Andric auto &Ctx = OutStreamer.getContext();
1662e8d8bef9SDimitry Andric MCSymbol *MILabel = Ctx.createTempSymbol();
1663e8d8bef9SDimitry Andric OutStreamer.emitLabel(MILabel);
1664e8d8bef9SDimitry Andric SM.recordStatepoint(*MILabel, MI);
1665e8d8bef9SDimitry Andric }
1666e8d8bef9SDimitry Andric
LowerFAULTING_OP(const MachineInstr & FaultingMI)1667e8d8bef9SDimitry Andric void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) {
1668e8d8bef9SDimitry Andric // FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>,
1669e8d8bef9SDimitry Andric // <opcode>, <operands>
1670e8d8bef9SDimitry Andric
1671e8d8bef9SDimitry Andric Register DefRegister = FaultingMI.getOperand(0).getReg();
1672e8d8bef9SDimitry Andric FaultMaps::FaultKind FK =
1673e8d8bef9SDimitry Andric static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm());
1674e8d8bef9SDimitry Andric MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol();
1675e8d8bef9SDimitry Andric unsigned Opcode = FaultingMI.getOperand(3).getImm();
1676e8d8bef9SDimitry Andric unsigned OperandsBeginIdx = 4;
1677e8d8bef9SDimitry Andric
1678e8d8bef9SDimitry Andric auto &Ctx = OutStreamer->getContext();
1679e8d8bef9SDimitry Andric MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1680e8d8bef9SDimitry Andric OutStreamer->emitLabel(FaultingLabel);
1681e8d8bef9SDimitry Andric
1682e8d8bef9SDimitry Andric assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!");
1683e8d8bef9SDimitry Andric FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1684e8d8bef9SDimitry Andric
1685e8d8bef9SDimitry Andric MCInst MI;
1686e8d8bef9SDimitry Andric MI.setOpcode(Opcode);
1687e8d8bef9SDimitry Andric
1688e8d8bef9SDimitry Andric if (DefRegister != (Register)0)
1689e8d8bef9SDimitry Andric MI.addOperand(MCOperand::createReg(DefRegister));
1690e8d8bef9SDimitry Andric
1691bdd1243dSDimitry Andric for (const MachineOperand &MO :
1692bdd1243dSDimitry Andric llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) {
1693e8d8bef9SDimitry Andric MCOperand Dest;
1694bdd1243dSDimitry Andric lowerOperand(MO, Dest);
1695e8d8bef9SDimitry Andric MI.addOperand(Dest);
1696e8d8bef9SDimitry Andric }
1697e8d8bef9SDimitry Andric
1698e8d8bef9SDimitry Andric OutStreamer->AddComment("on-fault: " + HandlerLabel->getName());
1699e8d8bef9SDimitry Andric OutStreamer->emitInstruction(MI, getSubtargetInfo());
1700e8d8bef9SDimitry Andric }
1701e8d8bef9SDimitry Andric
emitFMov0(const MachineInstr & MI)1702fe6060f1SDimitry Andric void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
17038bcb0991SDimitry Andric Register DestReg = MI.getOperand(0).getReg();
170481ad6265SDimitry Andric if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() &&
170506c3fb27SDimitry Andric STI->isNeonAvailable()) {
1706fe6060f1SDimitry Andric // Convert H/S register to corresponding D register
17070b57cec5SDimitry Andric if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
1708fe6060f1SDimitry Andric DestReg = AArch64::D0 + (DestReg - AArch64::H0);
17090b57cec5SDimitry Andric else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
1710fe6060f1SDimitry Andric DestReg = AArch64::D0 + (DestReg - AArch64::S0);
1711fe6060f1SDimitry Andric else
17120b57cec5SDimitry Andric assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
1713fe6060f1SDimitry Andric
17140b57cec5SDimitry Andric MCInst MOVI;
1715fe6060f1SDimitry Andric MOVI.setOpcode(AArch64::MOVID);
17160b57cec5SDimitry Andric MOVI.addOperand(MCOperand::createReg(DestReg));
17170b57cec5SDimitry Andric MOVI.addOperand(MCOperand::createImm(0));
17180b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MOVI);
17190b57cec5SDimitry Andric } else {
17200b57cec5SDimitry Andric MCInst FMov;
17210b57cec5SDimitry Andric switch (MI.getOpcode()) {
17220b57cec5SDimitry Andric default: llvm_unreachable("Unexpected opcode");
17230b57cec5SDimitry Andric case AArch64::FMOVH0:
172406c3fb27SDimitry Andric FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
172506c3fb27SDimitry Andric if (!STI->hasFullFP16())
172606c3fb27SDimitry Andric DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
17270b57cec5SDimitry Andric FMov.addOperand(MCOperand::createReg(DestReg));
17280b57cec5SDimitry Andric FMov.addOperand(MCOperand::createReg(AArch64::WZR));
17290b57cec5SDimitry Andric break;
17300b57cec5SDimitry Andric case AArch64::FMOVS0:
17310b57cec5SDimitry Andric FMov.setOpcode(AArch64::FMOVWSr);
17320b57cec5SDimitry Andric FMov.addOperand(MCOperand::createReg(DestReg));
17330b57cec5SDimitry Andric FMov.addOperand(MCOperand::createReg(AArch64::WZR));
17340b57cec5SDimitry Andric break;
17350b57cec5SDimitry Andric case AArch64::FMOVD0:
17360b57cec5SDimitry Andric FMov.setOpcode(AArch64::FMOVXDr);
17370b57cec5SDimitry Andric FMov.addOperand(MCOperand::createReg(DestReg));
17380b57cec5SDimitry Andric FMov.addOperand(MCOperand::createReg(AArch64::XZR));
17390b57cec5SDimitry Andric break;
17400b57cec5SDimitry Andric }
17410b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, FMov);
17420b57cec5SDimitry Andric }
17430b57cec5SDimitry Andric }
17440b57cec5SDimitry Andric
emitPtrauthDiscriminator(uint16_t Disc,unsigned AddrDisc,unsigned & InstsEmitted)17450fca6ea1SDimitry Andric unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
17460fca6ea1SDimitry Andric unsigned AddrDisc,
17470fca6ea1SDimitry Andric unsigned &InstsEmitted) {
17480fca6ea1SDimitry Andric // So far we've used NoRegister in pseudos. Now we need real encodings.
17490fca6ea1SDimitry Andric if (AddrDisc == AArch64::NoRegister)
17500fca6ea1SDimitry Andric AddrDisc = AArch64::XZR;
17510fca6ea1SDimitry Andric
17520fca6ea1SDimitry Andric // If there is no constant discriminator, there's no blend involved:
17530fca6ea1SDimitry Andric // just use the address discriminator register as-is (XZR or not).
17540fca6ea1SDimitry Andric if (!Disc)
17550fca6ea1SDimitry Andric return AddrDisc;
17560fca6ea1SDimitry Andric
17570fca6ea1SDimitry Andric // If there's only a constant discriminator, MOV it into x17.
17580fca6ea1SDimitry Andric if (AddrDisc == AArch64::XZR) {
17590fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
17600fca6ea1SDimitry Andric .addReg(AArch64::X17)
17610fca6ea1SDimitry Andric .addImm(Disc)
17620fca6ea1SDimitry Andric .addImm(/*shift=*/0));
17630fca6ea1SDimitry Andric ++InstsEmitted;
17640fca6ea1SDimitry Andric return AArch64::X17;
17650fca6ea1SDimitry Andric }
17660fca6ea1SDimitry Andric
17670fca6ea1SDimitry Andric // If there are both, emit a blend into x17.
17680fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
17690fca6ea1SDimitry Andric .addReg(AArch64::X17)
17700fca6ea1SDimitry Andric .addReg(AArch64::XZR)
17710fca6ea1SDimitry Andric .addReg(AddrDisc)
17720fca6ea1SDimitry Andric .addImm(0));
17730fca6ea1SDimitry Andric ++InstsEmitted;
17740fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
17750fca6ea1SDimitry Andric .addReg(AArch64::X17)
17760fca6ea1SDimitry Andric .addReg(AArch64::X17)
17770fca6ea1SDimitry Andric .addImm(Disc)
17780fca6ea1SDimitry Andric .addImm(/*shift=*/48));
17790fca6ea1SDimitry Andric ++InstsEmitted;
17800fca6ea1SDimitry Andric return AArch64::X17;
17810fca6ea1SDimitry Andric }
17820fca6ea1SDimitry Andric
emitPtrauthAuthResign(const MachineInstr * MI)17830fca6ea1SDimitry Andric void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
17840fca6ea1SDimitry Andric unsigned InstsEmitted = 0;
17850fca6ea1SDimitry Andric const bool IsAUTPAC = MI->getOpcode() == AArch64::AUTPAC;
17860fca6ea1SDimitry Andric
17870fca6ea1SDimitry Andric // We can expand AUT/AUTPAC into 3 possible sequences:
17880fca6ea1SDimitry Andric // - unchecked:
17890fca6ea1SDimitry Andric // autia x16, x0
17900fca6ea1SDimitry Andric // pacib x16, x1 ; if AUTPAC
17910fca6ea1SDimitry Andric //
17920fca6ea1SDimitry Andric // - checked and clearing:
17930fca6ea1SDimitry Andric // mov x17, x0
17940fca6ea1SDimitry Andric // movk x17, #disc, lsl #48
17950fca6ea1SDimitry Andric // autia x16, x17
17960fca6ea1SDimitry Andric // mov x17, x16
17970fca6ea1SDimitry Andric // xpaci x17
17980fca6ea1SDimitry Andric // cmp x16, x17
17990fca6ea1SDimitry Andric // b.eq Lsuccess
18000fca6ea1SDimitry Andric // mov x16, x17
18010fca6ea1SDimitry Andric // b Lend
18020fca6ea1SDimitry Andric // Lsuccess:
18030fca6ea1SDimitry Andric // mov x17, x1
18040fca6ea1SDimitry Andric // movk x17, #disc, lsl #48
18050fca6ea1SDimitry Andric // pacib x16, x17
18060fca6ea1SDimitry Andric // Lend:
18070fca6ea1SDimitry Andric // Where we only emit the AUT if we started with an AUT.
18080fca6ea1SDimitry Andric //
18090fca6ea1SDimitry Andric // - checked and trapping:
18100fca6ea1SDimitry Andric // mov x17, x0
18110fca6ea1SDimitry Andric // movk x17, #disc, lsl #48
18120fca6ea1SDimitry Andric // autia x16, x0
18130fca6ea1SDimitry Andric // mov x17, x16
18140fca6ea1SDimitry Andric // xpaci x17
18150fca6ea1SDimitry Andric // cmp x16, x17
18160fca6ea1SDimitry Andric // b.eq Lsuccess
18170fca6ea1SDimitry Andric // brk #<0xc470 + aut key>
18180fca6ea1SDimitry Andric // Lsuccess:
18190fca6ea1SDimitry Andric // mov x17, x1
18200fca6ea1SDimitry Andric // movk x17, #disc, lsl #48
18210fca6ea1SDimitry Andric // pacib x16, x17 ; if AUTPAC
18220fca6ea1SDimitry Andric // Where the b.eq skips over the trap if the PAC is valid.
18230fca6ea1SDimitry Andric //
18240fca6ea1SDimitry Andric // This sequence is expensive, but we need more information to be able to
18250fca6ea1SDimitry Andric // do better.
18260fca6ea1SDimitry Andric //
18270fca6ea1SDimitry Andric // We can't TBZ the poison bit because EnhancedPAC2 XORs the PAC bits
18280fca6ea1SDimitry Andric // on failure.
18290fca6ea1SDimitry Andric // We can't TST the PAC bits because we don't always know how the address
18300fca6ea1SDimitry Andric // space is setup for the target environment (and the bottom PAC bit is
18310fca6ea1SDimitry Andric // based on that).
18320fca6ea1SDimitry Andric // Either way, we also don't always know whether TBI is enabled or not for
18330fca6ea1SDimitry Andric // the specific target environment.
18340fca6ea1SDimitry Andric
18350fca6ea1SDimitry Andric // By default, auth/resign sequences check for auth failures.
18360fca6ea1SDimitry Andric bool ShouldCheck = true;
18370fca6ea1SDimitry Andric // In the checked sequence, we only trap if explicitly requested.
18380fca6ea1SDimitry Andric bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps");
18390fca6ea1SDimitry Andric
18400fca6ea1SDimitry Andric // On an FPAC CPU, you get traps whether you want them or not: there's
18410fca6ea1SDimitry Andric // no point in emitting checks or traps.
18420fca6ea1SDimitry Andric if (STI->hasFPAC())
18430fca6ea1SDimitry Andric ShouldCheck = ShouldTrap = false;
18440fca6ea1SDimitry Andric
18450fca6ea1SDimitry Andric // However, command-line flags can override this, for experimentation.
18460fca6ea1SDimitry Andric switch (PtrauthAuthChecks) {
18470fca6ea1SDimitry Andric case PtrauthCheckMode::Default:
18480fca6ea1SDimitry Andric break;
18490fca6ea1SDimitry Andric case PtrauthCheckMode::Unchecked:
18500fca6ea1SDimitry Andric ShouldCheck = ShouldTrap = false;
18510fca6ea1SDimitry Andric break;
18520fca6ea1SDimitry Andric case PtrauthCheckMode::Poison:
18530fca6ea1SDimitry Andric ShouldCheck = true;
18540fca6ea1SDimitry Andric ShouldTrap = false;
18550fca6ea1SDimitry Andric break;
18560fca6ea1SDimitry Andric case PtrauthCheckMode::Trap:
18570fca6ea1SDimitry Andric ShouldCheck = ShouldTrap = true;
18580fca6ea1SDimitry Andric break;
18590fca6ea1SDimitry Andric }
18600fca6ea1SDimitry Andric
18610fca6ea1SDimitry Andric auto AUTKey = (AArch64PACKey::ID)MI->getOperand(0).getImm();
18620fca6ea1SDimitry Andric uint64_t AUTDisc = MI->getOperand(1).getImm();
18630fca6ea1SDimitry Andric unsigned AUTAddrDisc = MI->getOperand(2).getReg();
18640fca6ea1SDimitry Andric
18650fca6ea1SDimitry Andric unsigned XPACOpc = getXPACOpcodeForKey(AUTKey);
18660fca6ea1SDimitry Andric
18670fca6ea1SDimitry Andric // Compute aut discriminator into x17
18680fca6ea1SDimitry Andric assert(isUInt<16>(AUTDisc));
18690fca6ea1SDimitry Andric unsigned AUTDiscReg =
18700fca6ea1SDimitry Andric emitPtrauthDiscriminator(AUTDisc, AUTAddrDisc, InstsEmitted);
18710fca6ea1SDimitry Andric bool AUTZero = AUTDiscReg == AArch64::XZR;
18720fca6ea1SDimitry Andric unsigned AUTOpc = getAUTOpcodeForKey(AUTKey, AUTZero);
18730fca6ea1SDimitry Andric
18740fca6ea1SDimitry Andric // autiza x16 ; if AUTZero
18750fca6ea1SDimitry Andric // autia x16, x17 ; if !AUTZero
18760fca6ea1SDimitry Andric MCInst AUTInst;
18770fca6ea1SDimitry Andric AUTInst.setOpcode(AUTOpc);
18780fca6ea1SDimitry Andric AUTInst.addOperand(MCOperand::createReg(AArch64::X16));
18790fca6ea1SDimitry Andric AUTInst.addOperand(MCOperand::createReg(AArch64::X16));
18800fca6ea1SDimitry Andric if (!AUTZero)
18810fca6ea1SDimitry Andric AUTInst.addOperand(MCOperand::createReg(AUTDiscReg));
18820fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, AUTInst);
18830fca6ea1SDimitry Andric ++InstsEmitted;
18840fca6ea1SDimitry Andric
18850fca6ea1SDimitry Andric // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done.
18860fca6ea1SDimitry Andric if (!IsAUTPAC && (!ShouldCheck || !ShouldTrap)) {
18870fca6ea1SDimitry Andric assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
18880fca6ea1SDimitry Andric return;
18890fca6ea1SDimitry Andric }
18900fca6ea1SDimitry Andric
18910fca6ea1SDimitry Andric MCSymbol *EndSym = nullptr;
18920fca6ea1SDimitry Andric
18930fca6ea1SDimitry Andric // Checked sequences do an additional strip-and-compare.
18940fca6ea1SDimitry Andric if (ShouldCheck) {
18950fca6ea1SDimitry Andric MCSymbol *SuccessSym = createTempSymbol("auth_success_");
18960fca6ea1SDimitry Andric
18970fca6ea1SDimitry Andric // XPAC has tied src/dst: use x17 as a temporary copy.
18980fca6ea1SDimitry Andric // mov x17, x16
18990fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
19000fca6ea1SDimitry Andric .addReg(AArch64::X17)
19010fca6ea1SDimitry Andric .addReg(AArch64::XZR)
19020fca6ea1SDimitry Andric .addReg(AArch64::X16)
19030fca6ea1SDimitry Andric .addImm(0));
19040fca6ea1SDimitry Andric ++InstsEmitted;
19050fca6ea1SDimitry Andric
19060fca6ea1SDimitry Andric // xpaci x17
19070fca6ea1SDimitry Andric EmitToStreamer(
19080fca6ea1SDimitry Andric *OutStreamer,
19090fca6ea1SDimitry Andric MCInstBuilder(XPACOpc).addReg(AArch64::X17).addReg(AArch64::X17));
19100fca6ea1SDimitry Andric ++InstsEmitted;
19110fca6ea1SDimitry Andric
19120fca6ea1SDimitry Andric // cmp x16, x17
19130fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs)
19140fca6ea1SDimitry Andric .addReg(AArch64::XZR)
19150fca6ea1SDimitry Andric .addReg(AArch64::X16)
19160fca6ea1SDimitry Andric .addReg(AArch64::X17)
19170fca6ea1SDimitry Andric .addImm(0));
19180fca6ea1SDimitry Andric ++InstsEmitted;
19190fca6ea1SDimitry Andric
19200fca6ea1SDimitry Andric // b.eq Lsuccess
19210fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::Bcc)
19220fca6ea1SDimitry Andric .addImm(AArch64CC::EQ)
19230fca6ea1SDimitry Andric .addExpr(MCSymbolRefExpr::create(
19240fca6ea1SDimitry Andric SuccessSym, OutContext)));
19250fca6ea1SDimitry Andric ++InstsEmitted;
19260fca6ea1SDimitry Andric
19270fca6ea1SDimitry Andric if (ShouldTrap) {
19280fca6ea1SDimitry Andric // Trapping sequences do a 'brk'.
19290fca6ea1SDimitry Andric // brk #<0xc470 + aut key>
19300fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer,
19310fca6ea1SDimitry Andric MCInstBuilder(AArch64::BRK).addImm(0xc470 | AUTKey));
19320fca6ea1SDimitry Andric ++InstsEmitted;
19330fca6ea1SDimitry Andric } else {
19340fca6ea1SDimitry Andric // Non-trapping checked sequences return the stripped result in x16,
19350fca6ea1SDimitry Andric // skipping over the PAC if there is one.
19360fca6ea1SDimitry Andric
19370fca6ea1SDimitry Andric // FIXME: can we simply return the AUT result, already in x16? without..
19380fca6ea1SDimitry Andric // ..traps this is usable as an oracle anyway, based on high bits
19390fca6ea1SDimitry Andric // mov x17, x16
19400fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
19410fca6ea1SDimitry Andric .addReg(AArch64::X16)
19420fca6ea1SDimitry Andric .addReg(AArch64::XZR)
19430fca6ea1SDimitry Andric .addReg(AArch64::X17)
19440fca6ea1SDimitry Andric .addImm(0));
19450fca6ea1SDimitry Andric ++InstsEmitted;
19460fca6ea1SDimitry Andric
19470fca6ea1SDimitry Andric if (IsAUTPAC) {
19480fca6ea1SDimitry Andric EndSym = createTempSymbol("resign_end_");
19490fca6ea1SDimitry Andric
19500fca6ea1SDimitry Andric // b Lend
19510fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B)
19520fca6ea1SDimitry Andric .addExpr(MCSymbolRefExpr::create(
19530fca6ea1SDimitry Andric EndSym, OutContext)));
19540fca6ea1SDimitry Andric ++InstsEmitted;
19550fca6ea1SDimitry Andric }
19560fca6ea1SDimitry Andric }
19570fca6ea1SDimitry Andric
19580fca6ea1SDimitry Andric // If the auth check succeeds, we can continue.
19590fca6ea1SDimitry Andric // Lsuccess:
19600fca6ea1SDimitry Andric OutStreamer->emitLabel(SuccessSym);
19610fca6ea1SDimitry Andric }
19620fca6ea1SDimitry Andric
19630fca6ea1SDimitry Andric // We already emitted unchecked and checked-but-non-trapping AUTs.
19640fca6ea1SDimitry Andric // That left us with trapping AUTs, and AUTPACs.
19650fca6ea1SDimitry Andric // Trapping AUTs don't need PAC: we're done.
19660fca6ea1SDimitry Andric if (!IsAUTPAC) {
19670fca6ea1SDimitry Andric assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
19680fca6ea1SDimitry Andric return;
19690fca6ea1SDimitry Andric }
19700fca6ea1SDimitry Andric
19710fca6ea1SDimitry Andric auto PACKey = (AArch64PACKey::ID)MI->getOperand(3).getImm();
19720fca6ea1SDimitry Andric uint64_t PACDisc = MI->getOperand(4).getImm();
19730fca6ea1SDimitry Andric unsigned PACAddrDisc = MI->getOperand(5).getReg();
19740fca6ea1SDimitry Andric
19750fca6ea1SDimitry Andric // Compute pac discriminator into x17
19760fca6ea1SDimitry Andric assert(isUInt<16>(PACDisc));
19770fca6ea1SDimitry Andric unsigned PACDiscReg =
19780fca6ea1SDimitry Andric emitPtrauthDiscriminator(PACDisc, PACAddrDisc, InstsEmitted);
19790fca6ea1SDimitry Andric bool PACZero = PACDiscReg == AArch64::XZR;
19800fca6ea1SDimitry Andric unsigned PACOpc = getPACOpcodeForKey(PACKey, PACZero);
19810fca6ea1SDimitry Andric
19820fca6ea1SDimitry Andric // pacizb x16 ; if PACZero
19830fca6ea1SDimitry Andric // pacib x16, x17 ; if !PACZero
19840fca6ea1SDimitry Andric MCInst PACInst;
19850fca6ea1SDimitry Andric PACInst.setOpcode(PACOpc);
19860fca6ea1SDimitry Andric PACInst.addOperand(MCOperand::createReg(AArch64::X16));
19870fca6ea1SDimitry Andric PACInst.addOperand(MCOperand::createReg(AArch64::X16));
19880fca6ea1SDimitry Andric if (!PACZero)
19890fca6ea1SDimitry Andric PACInst.addOperand(MCOperand::createReg(PACDiscReg));
19900fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, PACInst);
19910fca6ea1SDimitry Andric ++InstsEmitted;
19920fca6ea1SDimitry Andric
19930fca6ea1SDimitry Andric assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
19940fca6ea1SDimitry Andric // Lend:
19950fca6ea1SDimitry Andric if (EndSym)
19960fca6ea1SDimitry Andric OutStreamer->emitLabel(EndSym);
19970fca6ea1SDimitry Andric }
19980fca6ea1SDimitry Andric
emitPtrauthBranch(const MachineInstr * MI)19990fca6ea1SDimitry Andric void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
20000fca6ea1SDimitry Andric unsigned InstsEmitted = 0;
20010fca6ea1SDimitry Andric bool IsCall = MI->getOpcode() == AArch64::BLRA;
20020fca6ea1SDimitry Andric unsigned BrTarget = MI->getOperand(0).getReg();
20030fca6ea1SDimitry Andric
20040fca6ea1SDimitry Andric auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm();
20050fca6ea1SDimitry Andric assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
20060fca6ea1SDimitry Andric "Invalid auth call key");
20070fca6ea1SDimitry Andric
20080fca6ea1SDimitry Andric uint64_t Disc = MI->getOperand(2).getImm();
20090fca6ea1SDimitry Andric assert(isUInt<16>(Disc));
20100fca6ea1SDimitry Andric
20110fca6ea1SDimitry Andric unsigned AddrDisc = MI->getOperand(3).getReg();
20120fca6ea1SDimitry Andric
20130fca6ea1SDimitry Andric // Compute discriminator into x17
20140fca6ea1SDimitry Andric unsigned DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, InstsEmitted);
20150fca6ea1SDimitry Andric bool IsZeroDisc = DiscReg == AArch64::XZR;
20160fca6ea1SDimitry Andric
20170fca6ea1SDimitry Andric unsigned Opc;
20180fca6ea1SDimitry Andric if (IsCall) {
20190fca6ea1SDimitry Andric if (Key == AArch64PACKey::IA)
20200fca6ea1SDimitry Andric Opc = IsZeroDisc ? AArch64::BLRAAZ : AArch64::BLRAA;
20210fca6ea1SDimitry Andric else
20220fca6ea1SDimitry Andric Opc = IsZeroDisc ? AArch64::BLRABZ : AArch64::BLRAB;
20230fca6ea1SDimitry Andric } else {
20240fca6ea1SDimitry Andric if (Key == AArch64PACKey::IA)
20250fca6ea1SDimitry Andric Opc = IsZeroDisc ? AArch64::BRAAZ : AArch64::BRAA;
20260fca6ea1SDimitry Andric else
20270fca6ea1SDimitry Andric Opc = IsZeroDisc ? AArch64::BRABZ : AArch64::BRAB;
20280fca6ea1SDimitry Andric }
20290fca6ea1SDimitry Andric
20300fca6ea1SDimitry Andric MCInst BRInst;
20310fca6ea1SDimitry Andric BRInst.setOpcode(Opc);
20320fca6ea1SDimitry Andric BRInst.addOperand(MCOperand::createReg(BrTarget));
20330fca6ea1SDimitry Andric if (!IsZeroDisc)
20340fca6ea1SDimitry Andric BRInst.addOperand(MCOperand::createReg(DiscReg));
20350fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, BRInst);
20360fca6ea1SDimitry Andric ++InstsEmitted;
20370fca6ea1SDimitry Andric
20380fca6ea1SDimitry Andric assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4);
20390fca6ea1SDimitry Andric }
20400fca6ea1SDimitry Andric
20410fca6ea1SDimitry Andric const MCExpr *
lowerConstantPtrAuth(const ConstantPtrAuth & CPA)20420fca6ea1SDimitry Andric AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
20430fca6ea1SDimitry Andric MCContext &Ctx = OutContext;
20440fca6ea1SDimitry Andric
20450fca6ea1SDimitry Andric // Figure out the base symbol and the addend, if any.
20460fca6ea1SDimitry Andric APInt Offset(64, 0);
20470fca6ea1SDimitry Andric const Value *BaseGV = CPA.getPointer()->stripAndAccumulateConstantOffsets(
20480fca6ea1SDimitry Andric getDataLayout(), Offset, /*AllowNonInbounds=*/true);
20490fca6ea1SDimitry Andric
20500fca6ea1SDimitry Andric auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
20510fca6ea1SDimitry Andric
20520fca6ea1SDimitry Andric // If we can't understand the referenced ConstantExpr, there's nothing
20530fca6ea1SDimitry Andric // else we can do: emit an error.
20540fca6ea1SDimitry Andric if (!BaseGVB) {
20550fca6ea1SDimitry Andric BaseGV->getContext().emitError(
20560fca6ea1SDimitry Andric "cannot resolve target base/addend of ptrauth constant");
20570fca6ea1SDimitry Andric return nullptr;
20580fca6ea1SDimitry Andric }
20590fca6ea1SDimitry Andric
20600fca6ea1SDimitry Andric // If there is an addend, turn that into the appropriate MCExpr.
20610fca6ea1SDimitry Andric const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
20620fca6ea1SDimitry Andric if (Offset.sgt(0))
20630fca6ea1SDimitry Andric Sym = MCBinaryExpr::createAdd(
20640fca6ea1SDimitry Andric Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
20650fca6ea1SDimitry Andric else if (Offset.slt(0))
20660fca6ea1SDimitry Andric Sym = MCBinaryExpr::createSub(
20670fca6ea1SDimitry Andric Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
20680fca6ea1SDimitry Andric
20690fca6ea1SDimitry Andric uint64_t KeyID = CPA.getKey()->getZExtValue();
20700fca6ea1SDimitry Andric // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
20710fca6ea1SDimitry Andric // AArch64AuthMCExpr::printImpl, so fail fast.
20720fca6ea1SDimitry Andric if (KeyID > AArch64PACKey::LAST)
20730fca6ea1SDimitry Andric report_fatal_error("AArch64 PAC Key ID '" + Twine(KeyID) +
20740fca6ea1SDimitry Andric "' out of range [0, " +
20750fca6ea1SDimitry Andric Twine((unsigned)AArch64PACKey::LAST) + "]");
20760fca6ea1SDimitry Andric
20770fca6ea1SDimitry Andric uint64_t Disc = CPA.getDiscriminator()->getZExtValue();
20780fca6ea1SDimitry Andric if (!isUInt<16>(Disc))
20790fca6ea1SDimitry Andric report_fatal_error("AArch64 PAC Discriminator '" + Twine(Disc) +
20800fca6ea1SDimitry Andric "' out of range [0, 0xFFFF]");
20810fca6ea1SDimitry Andric
20820fca6ea1SDimitry Andric // Finally build the complete @AUTH expr.
20830fca6ea1SDimitry Andric return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
20840fca6ea1SDimitry Andric CPA.hasAddressDiscriminator(), Ctx);
20850fca6ea1SDimitry Andric }
20860fca6ea1SDimitry Andric
LowerLOADauthptrstatic(const MachineInstr & MI)20870fca6ea1SDimitry Andric void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
20880fca6ea1SDimitry Andric unsigned DstReg = MI.getOperand(0).getReg();
20890fca6ea1SDimitry Andric const MachineOperand &GAOp = MI.getOperand(1);
20900fca6ea1SDimitry Andric const uint64_t KeyC = MI.getOperand(2).getImm();
20910fca6ea1SDimitry Andric assert(KeyC <= AArch64PACKey::LAST &&
20920fca6ea1SDimitry Andric "key is out of range [0, AArch64PACKey::LAST]");
20930fca6ea1SDimitry Andric const auto Key = (AArch64PACKey::ID)KeyC;
20940fca6ea1SDimitry Andric const uint64_t Disc = MI.getOperand(3).getImm();
20950fca6ea1SDimitry Andric assert(isUInt<16>(Disc) &&
20960fca6ea1SDimitry Andric "constant discriminator is out of range [0, 0xffff]");
20970fca6ea1SDimitry Andric
20980fca6ea1SDimitry Andric // Emit instruction sequence like the following:
20990fca6ea1SDimitry Andric // ADRP x16, symbol$auth_ptr$key$disc
21000fca6ea1SDimitry Andric // LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc]
21010fca6ea1SDimitry Andric //
21020fca6ea1SDimitry Andric // Where the $auth_ptr$ symbol is the stub slot containing the signed pointer
21030fca6ea1SDimitry Andric // to symbol.
21040fca6ea1SDimitry Andric MCSymbol *AuthPtrStubSym;
21050fca6ea1SDimitry Andric if (TM.getTargetTriple().isOSBinFormatELF()) {
21060fca6ea1SDimitry Andric const auto &TLOF =
21070fca6ea1SDimitry Andric static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering());
21080fca6ea1SDimitry Andric
21090fca6ea1SDimitry Andric assert(GAOp.getOffset() == 0 &&
21100fca6ea1SDimitry Andric "non-zero offset for $auth_ptr$ stub slots is not supported");
21110fca6ea1SDimitry Andric const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
21120fca6ea1SDimitry Andric AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
21130fca6ea1SDimitry Andric } else {
21140fca6ea1SDimitry Andric assert(TM.getTargetTriple().isOSBinFormatMachO() &&
21150fca6ea1SDimitry Andric "LOADauthptrstatic is implemented only for MachO/ELF");
21160fca6ea1SDimitry Andric
21170fca6ea1SDimitry Andric const auto &TLOF = static_cast<const AArch64_MachoTargetObjectFile &>(
21180fca6ea1SDimitry Andric getObjFileLowering());
21190fca6ea1SDimitry Andric
21200fca6ea1SDimitry Andric assert(GAOp.getOffset() == 0 &&
21210fca6ea1SDimitry Andric "non-zero offset for $auth_ptr$ stub slots is not supported");
21220fca6ea1SDimitry Andric const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
21230fca6ea1SDimitry Andric AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc);
21240fca6ea1SDimitry Andric }
21250fca6ea1SDimitry Andric
21260fca6ea1SDimitry Andric MachineOperand StubMOHi =
21270fca6ea1SDimitry Andric MachineOperand::CreateMCSymbol(AuthPtrStubSym, AArch64II::MO_PAGE);
21280fca6ea1SDimitry Andric MachineOperand StubMOLo = MachineOperand::CreateMCSymbol(
21290fca6ea1SDimitry Andric AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
21300fca6ea1SDimitry Andric MCOperand StubMCHi, StubMCLo;
21310fca6ea1SDimitry Andric
21320fca6ea1SDimitry Andric MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
21330fca6ea1SDimitry Andric MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
21340fca6ea1SDimitry Andric
21350fca6ea1SDimitry Andric EmitToStreamer(
21360fca6ea1SDimitry Andric *OutStreamer,
21370fca6ea1SDimitry Andric MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi));
21380fca6ea1SDimitry Andric
21390fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui)
21400fca6ea1SDimitry Andric .addReg(DstReg)
21410fca6ea1SDimitry Andric .addReg(DstReg)
21420fca6ea1SDimitry Andric .addOperand(StubMCLo));
21430fca6ea1SDimitry Andric }
21440fca6ea1SDimitry Andric
LowerMOVaddrPAC(const MachineInstr & MI)21450fca6ea1SDimitry Andric void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
21460fca6ea1SDimitry Andric unsigned InstsEmitted = 0;
21470fca6ea1SDimitry Andric auto EmitAndIncrement = [this, &InstsEmitted](const MCInst &Inst) {
21480fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, Inst);
21490fca6ea1SDimitry Andric ++InstsEmitted;
21500fca6ea1SDimitry Andric };
21510fca6ea1SDimitry Andric
21520fca6ea1SDimitry Andric const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC;
21530fca6ea1SDimitry Andric MachineOperand GAOp = MI.getOperand(0);
21540fca6ea1SDimitry Andric const uint64_t KeyC = MI.getOperand(1).getImm();
21550fca6ea1SDimitry Andric assert(KeyC <= AArch64PACKey::LAST &&
21560fca6ea1SDimitry Andric "key is out of range [0, AArch64PACKey::LAST]");
21570fca6ea1SDimitry Andric const auto Key = (AArch64PACKey::ID)KeyC;
21580fca6ea1SDimitry Andric const unsigned AddrDisc = MI.getOperand(2).getReg();
21590fca6ea1SDimitry Andric const uint64_t Disc = MI.getOperand(3).getImm();
21600fca6ea1SDimitry Andric assert(isUInt<16>(Disc) &&
21610fca6ea1SDimitry Andric "constant discriminator is out of range [0, 0xffff]");
21620fca6ea1SDimitry Andric
21630fca6ea1SDimitry Andric const int64_t Offset = GAOp.getOffset();
21640fca6ea1SDimitry Andric GAOp.setOffset(0);
21650fca6ea1SDimitry Andric
21660fca6ea1SDimitry Andric // Emit:
21670fca6ea1SDimitry Andric // target materialization:
21680fca6ea1SDimitry Andric // - via GOT:
21690fca6ea1SDimitry Andric // adrp x16, :got:target
21700fca6ea1SDimitry Andric // ldr x16, [x16, :got_lo12:target]
21710fca6ea1SDimitry Andric // add offset to x16 if offset != 0
21720fca6ea1SDimitry Andric //
21730fca6ea1SDimitry Andric // - direct:
21740fca6ea1SDimitry Andric // adrp x16, target
21750fca6ea1SDimitry Andric // add x16, x16, :lo12:target
21760fca6ea1SDimitry Andric // add offset to x16 if offset != 0
21770fca6ea1SDimitry Andric //
21780fca6ea1SDimitry Andric // add offset to x16:
21790fca6ea1SDimitry Andric // - abs(offset) fits 24 bits:
21800fca6ea1SDimitry Andric // add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions)
21810fca6ea1SDimitry Andric // - abs(offset) does not fit 24 bits:
21820fca6ea1SDimitry Andric // - offset < 0:
21830fca6ea1SDimitry Andric // movn+movk sequence filling x17 register with the offset (up to 4
21840fca6ea1SDimitry Andric // instructions)
21850fca6ea1SDimitry Andric // add x16, x16, x17
21860fca6ea1SDimitry Andric // - offset > 0:
21870fca6ea1SDimitry Andric // movz+movk sequence filling x17 register with the offset (up to 4
21880fca6ea1SDimitry Andric // instructions)
21890fca6ea1SDimitry Andric // add x16, x16, x17
21900fca6ea1SDimitry Andric //
21910fca6ea1SDimitry Andric // signing:
21920fca6ea1SDimitry Andric // - 0 discriminator:
21930fca6ea1SDimitry Andric // paciza x16
21940fca6ea1SDimitry Andric // - Non-0 discriminator, no address discriminator:
21950fca6ea1SDimitry Andric // mov x17, #Disc
21960fca6ea1SDimitry Andric // pacia x16, x17
21970fca6ea1SDimitry Andric // - address discriminator (with potentially folded immediate discriminator):
21980fca6ea1SDimitry Andric // pacia x16, xAddrDisc
21990fca6ea1SDimitry Andric
22000fca6ea1SDimitry Andric MachineOperand GAMOHi(GAOp), GAMOLo(GAOp);
22010fca6ea1SDimitry Andric MCOperand GAMCHi, GAMCLo;
22020fca6ea1SDimitry Andric
22030fca6ea1SDimitry Andric GAMOHi.setTargetFlags(AArch64II::MO_PAGE);
22040fca6ea1SDimitry Andric GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
22050fca6ea1SDimitry Andric if (IsGOTLoad) {
22060fca6ea1SDimitry Andric GAMOHi.addTargetFlag(AArch64II::MO_GOT);
22070fca6ea1SDimitry Andric GAMOLo.addTargetFlag(AArch64II::MO_GOT);
22080fca6ea1SDimitry Andric }
22090fca6ea1SDimitry Andric
22100fca6ea1SDimitry Andric MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
22110fca6ea1SDimitry Andric MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
22120fca6ea1SDimitry Andric
22130fca6ea1SDimitry Andric EmitAndIncrement(
22140fca6ea1SDimitry Andric MCInstBuilder(AArch64::ADRP).addReg(AArch64::X16).addOperand(GAMCHi));
22150fca6ea1SDimitry Andric
22160fca6ea1SDimitry Andric if (IsGOTLoad) {
22170fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::LDRXui)
22180fca6ea1SDimitry Andric .addReg(AArch64::X16)
22190fca6ea1SDimitry Andric .addReg(AArch64::X16)
22200fca6ea1SDimitry Andric .addOperand(GAMCLo));
22210fca6ea1SDimitry Andric } else {
22220fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::ADDXri)
22230fca6ea1SDimitry Andric .addReg(AArch64::X16)
22240fca6ea1SDimitry Andric .addReg(AArch64::X16)
22250fca6ea1SDimitry Andric .addOperand(GAMCLo)
22260fca6ea1SDimitry Andric .addImm(0));
22270fca6ea1SDimitry Andric }
22280fca6ea1SDimitry Andric
22290fca6ea1SDimitry Andric if (Offset != 0) {
22300fca6ea1SDimitry Andric const uint64_t AbsOffset = (Offset > 0 ? Offset : -((uint64_t)Offset));
22310fca6ea1SDimitry Andric const bool IsNeg = Offset < 0;
22320fca6ea1SDimitry Andric if (isUInt<24>(AbsOffset)) {
22330fca6ea1SDimitry Andric for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
22340fca6ea1SDimitry Andric BitPos += 12) {
22350fca6ea1SDimitry Andric EmitAndIncrement(
22360fca6ea1SDimitry Andric MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri)
22370fca6ea1SDimitry Andric .addReg(AArch64::X16)
22380fca6ea1SDimitry Andric .addReg(AArch64::X16)
22390fca6ea1SDimitry Andric .addImm((AbsOffset >> BitPos) & 0xfff)
22400fca6ea1SDimitry Andric .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
22410fca6ea1SDimitry Andric }
22420fca6ea1SDimitry Andric } else {
22430fca6ea1SDimitry Andric const uint64_t UOffset = Offset;
22440fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
22450fca6ea1SDimitry Andric .addReg(AArch64::X17)
22460fca6ea1SDimitry Andric .addImm((IsNeg ? ~UOffset : UOffset) & 0xffff)
22470fca6ea1SDimitry Andric .addImm(/*shift=*/0));
22480fca6ea1SDimitry Andric auto NeedMovk = [IsNeg, UOffset](int BitPos) -> bool {
22490fca6ea1SDimitry Andric assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
22500fca6ea1SDimitry Andric uint64_t Shifted = UOffset >> BitPos;
22510fca6ea1SDimitry Andric if (!IsNeg)
22520fca6ea1SDimitry Andric return Shifted != 0;
22530fca6ea1SDimitry Andric for (int I = 0; I != 64 - BitPos; I += 16)
22540fca6ea1SDimitry Andric if (((Shifted >> I) & 0xffff) != 0xffff)
22550fca6ea1SDimitry Andric return true;
22560fca6ea1SDimitry Andric return false;
22570fca6ea1SDimitry Andric };
22580fca6ea1SDimitry Andric for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) {
22590fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
22600fca6ea1SDimitry Andric .addReg(AArch64::X17)
22610fca6ea1SDimitry Andric .addReg(AArch64::X17)
22620fca6ea1SDimitry Andric .addImm((UOffset >> BitPos) & 0xffff)
22630fca6ea1SDimitry Andric .addImm(/*shift=*/BitPos));
22640fca6ea1SDimitry Andric }
22650fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::ADDXrs)
22660fca6ea1SDimitry Andric .addReg(AArch64::X16)
22670fca6ea1SDimitry Andric .addReg(AArch64::X16)
22680fca6ea1SDimitry Andric .addReg(AArch64::X17)
22690fca6ea1SDimitry Andric .addImm(/*shift=*/0));
22700fca6ea1SDimitry Andric }
22710fca6ea1SDimitry Andric }
22720fca6ea1SDimitry Andric
22730fca6ea1SDimitry Andric unsigned DiscReg = AddrDisc;
22740fca6ea1SDimitry Andric if (Disc != 0) {
22750fca6ea1SDimitry Andric if (AddrDisc != AArch64::XZR) {
22760fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::ORRXrs)
22770fca6ea1SDimitry Andric .addReg(AArch64::X17)
22780fca6ea1SDimitry Andric .addReg(AArch64::XZR)
22790fca6ea1SDimitry Andric .addReg(AddrDisc)
22800fca6ea1SDimitry Andric .addImm(0));
22810fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
22820fca6ea1SDimitry Andric .addReg(AArch64::X17)
22830fca6ea1SDimitry Andric .addReg(AArch64::X17)
22840fca6ea1SDimitry Andric .addImm(Disc)
22850fca6ea1SDimitry Andric .addImm(/*shift=*/48));
22860fca6ea1SDimitry Andric } else {
22870fca6ea1SDimitry Andric EmitAndIncrement(MCInstBuilder(AArch64::MOVZXi)
22880fca6ea1SDimitry Andric .addReg(AArch64::X17)
22890fca6ea1SDimitry Andric .addImm(Disc)
22900fca6ea1SDimitry Andric .addImm(/*shift=*/0));
22910fca6ea1SDimitry Andric }
22920fca6ea1SDimitry Andric DiscReg = AArch64::X17;
22930fca6ea1SDimitry Andric }
22940fca6ea1SDimitry Andric
22950fca6ea1SDimitry Andric auto MIB = MCInstBuilder(getPACOpcodeForKey(Key, DiscReg == AArch64::XZR))
22960fca6ea1SDimitry Andric .addReg(AArch64::X16)
22970fca6ea1SDimitry Andric .addReg(AArch64::X16);
22980fca6ea1SDimitry Andric if (DiscReg != AArch64::XZR)
22990fca6ea1SDimitry Andric MIB.addReg(DiscReg);
23000fca6ea1SDimitry Andric EmitAndIncrement(MIB);
23010fca6ea1SDimitry Andric
23020fca6ea1SDimitry Andric assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4);
23030fca6ea1SDimitry Andric }
23040fca6ea1SDimitry Andric
23050fca6ea1SDimitry Andric const MCExpr *
lowerBlockAddressConstant(const BlockAddress & BA)23060fca6ea1SDimitry Andric AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) {
23070fca6ea1SDimitry Andric const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant(BA);
23080fca6ea1SDimitry Andric const Function &Fn = *BA.getFunction();
23090fca6ea1SDimitry Andric
23100fca6ea1SDimitry Andric if (std::optional<uint16_t> BADisc =
23110fca6ea1SDimitry Andric STI->getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn))
23120fca6ea1SDimitry Andric return AArch64AuthMCExpr::create(BAE, *BADisc, AArch64PACKey::IA,
23130fca6ea1SDimitry Andric /*HasAddressDiversity=*/false, OutContext);
23140fca6ea1SDimitry Andric
23150fca6ea1SDimitry Andric return BAE;
23160fca6ea1SDimitry Andric }
23170fca6ea1SDimitry Andric
23180b57cec5SDimitry Andric // Simple pseudo-instructions have their lowering (with expansion to real
23190b57cec5SDimitry Andric // instructions) auto-generated.
23200b57cec5SDimitry Andric #include "AArch64GenMCPseudoLowering.inc"
23210b57cec5SDimitry Andric
emitInstruction(const MachineInstr * MI)23225ffd83dbSDimitry Andric void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
2323753f127fSDimitry Andric AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
2324753f127fSDimitry Andric
23250b57cec5SDimitry Andric // Do any auto-generated pseudo lowerings.
23260b57cec5SDimitry Andric if (emitPseudoExpansionLowering(*OutStreamer, MI))
23270b57cec5SDimitry Andric return;
23280b57cec5SDimitry Andric
23290eae32dcSDimitry Andric if (MI->getOpcode() == AArch64::ADRP) {
23300eae32dcSDimitry Andric for (auto &Opd : MI->operands()) {
23310eae32dcSDimitry Andric if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) ==
23320eae32dcSDimitry Andric "swift_async_extendedFramePointerFlags") {
23330eae32dcSDimitry Andric ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true;
23340eae32dcSDimitry Andric }
23350eae32dcSDimitry Andric }
23360eae32dcSDimitry Andric }
23370eae32dcSDimitry Andric
23380b57cec5SDimitry Andric if (AArch64FI->getLOHRelated().count(MI)) {
23390b57cec5SDimitry Andric // Generate a label for LOH related instruction
23400b57cec5SDimitry Andric MCSymbol *LOHLabel = createTempSymbol("loh");
23410b57cec5SDimitry Andric // Associate the instruction with the label
23420b57cec5SDimitry Andric LOHInstToLabel[MI] = LOHLabel;
23435ffd83dbSDimitry Andric OutStreamer->emitLabel(LOHLabel);
23440b57cec5SDimitry Andric }
23450b57cec5SDimitry Andric
23460b57cec5SDimitry Andric AArch64TargetStreamer *TS =
23470b57cec5SDimitry Andric static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
23480b57cec5SDimitry Andric // Do any manual lowerings.
23490b57cec5SDimitry Andric switch (MI->getOpcode()) {
23500b57cec5SDimitry Andric default:
23510b57cec5SDimitry Andric break;
235213138422SDimitry Andric case AArch64::HINT: {
235313138422SDimitry Andric // CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for
235413138422SDimitry Andric // -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be
235513138422SDimitry Andric // non-empty. If MI is the initial BTI, place the
235613138422SDimitry Andric // __patchable_function_entries label after BTI.
235713138422SDimitry Andric if (CurrentPatchableFunctionEntrySym &&
235813138422SDimitry Andric CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
235913138422SDimitry Andric MI == &MF->front().front()) {
236013138422SDimitry Andric int64_t Imm = MI->getOperand(0).getImm();
236113138422SDimitry Andric if ((Imm & 32) && (Imm & 6)) {
236213138422SDimitry Andric MCInst Inst;
236313138422SDimitry Andric MCInstLowering.Lower(MI, Inst);
236413138422SDimitry Andric EmitToStreamer(*OutStreamer, Inst);
236513138422SDimitry Andric CurrentPatchableFunctionEntrySym = createTempSymbol("patch");
23665ffd83dbSDimitry Andric OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym);
236713138422SDimitry Andric return;
236813138422SDimitry Andric }
236913138422SDimitry Andric }
237013138422SDimitry Andric break;
237113138422SDimitry Andric }
23720b57cec5SDimitry Andric case AArch64::MOVMCSym: {
23738bcb0991SDimitry Andric Register DestReg = MI->getOperand(0).getReg();
23740b57cec5SDimitry Andric const MachineOperand &MO_Sym = MI->getOperand(1);
23750b57cec5SDimitry Andric MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
23760b57cec5SDimitry Andric MCOperand Hi_MCSym, Lo_MCSym;
23770b57cec5SDimitry Andric
23780b57cec5SDimitry Andric Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
23790b57cec5SDimitry Andric Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
23800b57cec5SDimitry Andric
23810b57cec5SDimitry Andric MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
23820b57cec5SDimitry Andric MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
23830b57cec5SDimitry Andric
23840b57cec5SDimitry Andric MCInst MovZ;
23850b57cec5SDimitry Andric MovZ.setOpcode(AArch64::MOVZXi);
23860b57cec5SDimitry Andric MovZ.addOperand(MCOperand::createReg(DestReg));
23870b57cec5SDimitry Andric MovZ.addOperand(Hi_MCSym);
23880b57cec5SDimitry Andric MovZ.addOperand(MCOperand::createImm(16));
23890b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MovZ);
23900b57cec5SDimitry Andric
23910b57cec5SDimitry Andric MCInst MovK;
23920b57cec5SDimitry Andric MovK.setOpcode(AArch64::MOVKXi);
23930b57cec5SDimitry Andric MovK.addOperand(MCOperand::createReg(DestReg));
23940b57cec5SDimitry Andric MovK.addOperand(MCOperand::createReg(DestReg));
23950b57cec5SDimitry Andric MovK.addOperand(Lo_MCSym);
23960b57cec5SDimitry Andric MovK.addOperand(MCOperand::createImm(0));
23970b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MovK);
23980b57cec5SDimitry Andric return;
23990b57cec5SDimitry Andric }
24000b57cec5SDimitry Andric case AArch64::MOVIv2d_ns:
24015f757f3fSDimitry Andric // It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0".
24025f757f3fSDimitry Andric // as movi is more efficient across all cores. Newer cores can eliminate
24035f757f3fSDimitry Andric // fmovs early and there is no difference with movi, but this not true for
24045f757f3fSDimitry Andric // all implementations.
24055f757f3fSDimitry Andric //
24065f757f3fSDimitry Andric // The floating-point version doesn't quite work in rare cases on older
24075f757f3fSDimitry Andric // CPUs, so on those targets we lower this instruction to movi.16b instead.
24080b57cec5SDimitry Andric if (STI->hasZeroCycleZeroingFPWorkaround() &&
24090b57cec5SDimitry Andric MI->getOperand(1).getImm() == 0) {
24100b57cec5SDimitry Andric MCInst TmpInst;
24110b57cec5SDimitry Andric TmpInst.setOpcode(AArch64::MOVIv16b_ns);
24120b57cec5SDimitry Andric TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
24130b57cec5SDimitry Andric TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
24140b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
24150b57cec5SDimitry Andric return;
24160b57cec5SDimitry Andric }
24170b57cec5SDimitry Andric break;
24180b57cec5SDimitry Andric
2419fe6060f1SDimitry Andric case AArch64::DBG_VALUE:
242081ad6265SDimitry Andric case AArch64::DBG_VALUE_LIST:
24210b57cec5SDimitry Andric if (isVerbose() && OutStreamer->hasRawTextSupport()) {
24220b57cec5SDimitry Andric SmallString<128> TmpStr;
24230b57cec5SDimitry Andric raw_svector_ostream OS(TmpStr);
24240b57cec5SDimitry Andric PrintDebugValueComment(MI, OS);
24255ffd83dbSDimitry Andric OutStreamer->emitRawText(StringRef(OS.str()));
24260b57cec5SDimitry Andric }
24270b57cec5SDimitry Andric return;
24280b57cec5SDimitry Andric
24290b57cec5SDimitry Andric case AArch64::EMITBKEY: {
24300b57cec5SDimitry Andric ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
24310b57cec5SDimitry Andric if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
24320b57cec5SDimitry Andric ExceptionHandlingType != ExceptionHandling::ARM)
24330b57cec5SDimitry Andric return;
24340b57cec5SDimitry Andric
2435fe6060f1SDimitry Andric if (getFunctionCFISectionType(*MF) == CFISection::None)
24360b57cec5SDimitry Andric return;
24370b57cec5SDimitry Andric
24385ffd83dbSDimitry Andric OutStreamer->emitCFIBKeyFrame();
24390b57cec5SDimitry Andric return;
24400b57cec5SDimitry Andric }
244181ad6265SDimitry Andric
244281ad6265SDimitry Andric case AArch64::EMITMTETAGGED: {
244381ad6265SDimitry Andric ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
244481ad6265SDimitry Andric if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
244581ad6265SDimitry Andric ExceptionHandlingType != ExceptionHandling::ARM)
244681ad6265SDimitry Andric return;
244781ad6265SDimitry Andric
244881ad6265SDimitry Andric if (getFunctionCFISectionType(*MF) != CFISection::None)
244981ad6265SDimitry Andric OutStreamer->emitCFIMTETaggedFrame();
245081ad6265SDimitry Andric return;
24510b57cec5SDimitry Andric }
24520b57cec5SDimitry Andric
24530fca6ea1SDimitry Andric case AArch64::AUT:
24540fca6ea1SDimitry Andric case AArch64::AUTPAC:
24550fca6ea1SDimitry Andric emitPtrauthAuthResign(MI);
24560fca6ea1SDimitry Andric return;
24570fca6ea1SDimitry Andric
24580fca6ea1SDimitry Andric case AArch64::LOADauthptrstatic:
24590fca6ea1SDimitry Andric LowerLOADauthptrstatic(*MI);
24600fca6ea1SDimitry Andric return;
24610fca6ea1SDimitry Andric
24620fca6ea1SDimitry Andric case AArch64::LOADgotPAC:
24630fca6ea1SDimitry Andric case AArch64::MOVaddrPAC:
24640fca6ea1SDimitry Andric LowerMOVaddrPAC(*MI);
24650fca6ea1SDimitry Andric return;
24660fca6ea1SDimitry Andric
24670fca6ea1SDimitry Andric case AArch64::BRA:
24680fca6ea1SDimitry Andric case AArch64::BLRA:
24690fca6ea1SDimitry Andric emitPtrauthBranch(MI);
24700fca6ea1SDimitry Andric return;
24710fca6ea1SDimitry Andric
24720b57cec5SDimitry Andric // Tail calls use pseudo instructions so they have the proper code-gen
24730b57cec5SDimitry Andric // attributes (isCall, isReturn, etc.). We lower them to the real
24740b57cec5SDimitry Andric // instruction here.
24750fca6ea1SDimitry Andric case AArch64::AUTH_TCRETURN:
24760fca6ea1SDimitry Andric case AArch64::AUTH_TCRETURN_BTI: {
24770fca6ea1SDimitry Andric const uint64_t Key = MI->getOperand(2).getImm();
24780fca6ea1SDimitry Andric assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
24790fca6ea1SDimitry Andric "Invalid auth key for tail-call return");
24800fca6ea1SDimitry Andric
24810fca6ea1SDimitry Andric const uint64_t Disc = MI->getOperand(3).getImm();
24820fca6ea1SDimitry Andric assert(isUInt<16>(Disc) && "Integer discriminator is too wide");
24830fca6ea1SDimitry Andric
24840fca6ea1SDimitry Andric Register AddrDisc = MI->getOperand(4).getReg();
24850fca6ea1SDimitry Andric
24860fca6ea1SDimitry Andric Register ScratchReg = MI->getOperand(0).getReg() == AArch64::X16
24870fca6ea1SDimitry Andric ? AArch64::X17
24880fca6ea1SDimitry Andric : AArch64::X16;
24890fca6ea1SDimitry Andric
24900fca6ea1SDimitry Andric unsigned DiscReg = AddrDisc;
24910fca6ea1SDimitry Andric if (Disc) {
24920fca6ea1SDimitry Andric if (AddrDisc != AArch64::NoRegister) {
24930fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs)
24940fca6ea1SDimitry Andric .addReg(ScratchReg)
24950fca6ea1SDimitry Andric .addReg(AArch64::XZR)
24960fca6ea1SDimitry Andric .addReg(AddrDisc)
24970fca6ea1SDimitry Andric .addImm(0));
24980fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
24990fca6ea1SDimitry Andric .addReg(ScratchReg)
25000fca6ea1SDimitry Andric .addReg(ScratchReg)
25010fca6ea1SDimitry Andric .addImm(Disc)
25020fca6ea1SDimitry Andric .addImm(/*shift=*/48));
25030fca6ea1SDimitry Andric } else {
25040fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
25050fca6ea1SDimitry Andric .addReg(ScratchReg)
25060fca6ea1SDimitry Andric .addImm(Disc)
25070fca6ea1SDimitry Andric .addImm(/*shift=*/0));
25080fca6ea1SDimitry Andric }
25090fca6ea1SDimitry Andric DiscReg = ScratchReg;
25100fca6ea1SDimitry Andric }
25110fca6ea1SDimitry Andric
25120fca6ea1SDimitry Andric const bool IsZero = DiscReg == AArch64::NoRegister;
25130fca6ea1SDimitry Andric const unsigned Opcodes[2][2] = {{AArch64::BRAA, AArch64::BRAAZ},
25140fca6ea1SDimitry Andric {AArch64::BRAB, AArch64::BRABZ}};
25150fca6ea1SDimitry Andric
25160fca6ea1SDimitry Andric MCInst TmpInst;
25170fca6ea1SDimitry Andric TmpInst.setOpcode(Opcodes[Key][IsZero]);
25180fca6ea1SDimitry Andric TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
25190fca6ea1SDimitry Andric if (!IsZero)
25200fca6ea1SDimitry Andric TmpInst.addOperand(MCOperand::createReg(DiscReg));
25210fca6ea1SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
25220fca6ea1SDimitry Andric return;
25230fca6ea1SDimitry Andric }
25240fca6ea1SDimitry Andric
25250b57cec5SDimitry Andric case AArch64::TCRETURNri:
25260fca6ea1SDimitry Andric case AArch64::TCRETURNrix16x17:
25270fca6ea1SDimitry Andric case AArch64::TCRETURNrix17:
25280fca6ea1SDimitry Andric case AArch64::TCRETURNrinotx16:
25290b57cec5SDimitry Andric case AArch64::TCRETURNriALL: {
25300b57cec5SDimitry Andric MCInst TmpInst;
25310b57cec5SDimitry Andric TmpInst.setOpcode(AArch64::BR);
25320b57cec5SDimitry Andric TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
25330b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
25340b57cec5SDimitry Andric return;
25350b57cec5SDimitry Andric }
25360b57cec5SDimitry Andric case AArch64::TCRETURNdi: {
25370b57cec5SDimitry Andric MCOperand Dest;
25380b57cec5SDimitry Andric MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
25390b57cec5SDimitry Andric MCInst TmpInst;
25400b57cec5SDimitry Andric TmpInst.setOpcode(AArch64::B);
25410b57cec5SDimitry Andric TmpInst.addOperand(Dest);
25420b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
25430b57cec5SDimitry Andric return;
25440b57cec5SDimitry Andric }
25455ffd83dbSDimitry Andric case AArch64::SpeculationBarrierISBDSBEndBB: {
25465ffd83dbSDimitry Andric // Print DSB SYS + ISB
25475ffd83dbSDimitry Andric MCInst TmpInstDSB;
25485ffd83dbSDimitry Andric TmpInstDSB.setOpcode(AArch64::DSB);
25495ffd83dbSDimitry Andric TmpInstDSB.addOperand(MCOperand::createImm(0xf));
25505ffd83dbSDimitry Andric EmitToStreamer(*OutStreamer, TmpInstDSB);
25515ffd83dbSDimitry Andric MCInst TmpInstISB;
25525ffd83dbSDimitry Andric TmpInstISB.setOpcode(AArch64::ISB);
25535ffd83dbSDimitry Andric TmpInstISB.addOperand(MCOperand::createImm(0xf));
25545ffd83dbSDimitry Andric EmitToStreamer(*OutStreamer, TmpInstISB);
25555ffd83dbSDimitry Andric return;
25565ffd83dbSDimitry Andric }
25575ffd83dbSDimitry Andric case AArch64::SpeculationBarrierSBEndBB: {
25585ffd83dbSDimitry Andric // Print SB
25595ffd83dbSDimitry Andric MCInst TmpInstSB;
25605ffd83dbSDimitry Andric TmpInstSB.setOpcode(AArch64::SB);
25615ffd83dbSDimitry Andric EmitToStreamer(*OutStreamer, TmpInstSB);
25625ffd83dbSDimitry Andric return;
25635ffd83dbSDimitry Andric }
25640b57cec5SDimitry Andric case AArch64::TLSDESC_CALLSEQ: {
25650b57cec5SDimitry Andric /// lower this to:
25660b57cec5SDimitry Andric /// adrp x0, :tlsdesc:var
25670b57cec5SDimitry Andric /// ldr x1, [x0, #:tlsdesc_lo12:var]
25680b57cec5SDimitry Andric /// add x0, x0, #:tlsdesc_lo12:var
25690b57cec5SDimitry Andric /// .tlsdesccall var
25700b57cec5SDimitry Andric /// blr x1
25710b57cec5SDimitry Andric /// (TPIDR_EL0 offset now in x0)
25720b57cec5SDimitry Andric const MachineOperand &MO_Sym = MI->getOperand(0);
25730b57cec5SDimitry Andric MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
25740b57cec5SDimitry Andric MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
25750b57cec5SDimitry Andric MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
25760b57cec5SDimitry Andric MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
25770b57cec5SDimitry Andric MCInstLowering.lowerOperand(MO_Sym, Sym);
25780b57cec5SDimitry Andric MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
25790b57cec5SDimitry Andric MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
25800b57cec5SDimitry Andric
25810b57cec5SDimitry Andric MCInst Adrp;
25820b57cec5SDimitry Andric Adrp.setOpcode(AArch64::ADRP);
25830b57cec5SDimitry Andric Adrp.addOperand(MCOperand::createReg(AArch64::X0));
25840b57cec5SDimitry Andric Adrp.addOperand(SymTLSDesc);
25850b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, Adrp);
25860b57cec5SDimitry Andric
25870b57cec5SDimitry Andric MCInst Ldr;
2588e8d8bef9SDimitry Andric if (STI->isTargetILP32()) {
2589e8d8bef9SDimitry Andric Ldr.setOpcode(AArch64::LDRWui);
2590e8d8bef9SDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::W1));
2591e8d8bef9SDimitry Andric } else {
25920b57cec5SDimitry Andric Ldr.setOpcode(AArch64::LDRXui);
25930b57cec5SDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::X1));
2594e8d8bef9SDimitry Andric }
25950b57cec5SDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::X0));
25960b57cec5SDimitry Andric Ldr.addOperand(SymTLSDescLo12);
25970b57cec5SDimitry Andric Ldr.addOperand(MCOperand::createImm(0));
25980b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, Ldr);
25990b57cec5SDimitry Andric
26000b57cec5SDimitry Andric MCInst Add;
2601e8d8bef9SDimitry Andric if (STI->isTargetILP32()) {
2602e8d8bef9SDimitry Andric Add.setOpcode(AArch64::ADDWri);
2603e8d8bef9SDimitry Andric Add.addOperand(MCOperand::createReg(AArch64::W0));
2604e8d8bef9SDimitry Andric Add.addOperand(MCOperand::createReg(AArch64::W0));
2605e8d8bef9SDimitry Andric } else {
26060b57cec5SDimitry Andric Add.setOpcode(AArch64::ADDXri);
26070b57cec5SDimitry Andric Add.addOperand(MCOperand::createReg(AArch64::X0));
26080b57cec5SDimitry Andric Add.addOperand(MCOperand::createReg(AArch64::X0));
2609e8d8bef9SDimitry Andric }
26100b57cec5SDimitry Andric Add.addOperand(SymTLSDescLo12);
26110b57cec5SDimitry Andric Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
26120b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, Add);
26130b57cec5SDimitry Andric
26140b57cec5SDimitry Andric // Emit a relocation-annotation. This expands to no code, but requests
26150b57cec5SDimitry Andric // the following instruction gets an R_AARCH64_TLSDESC_CALL.
26160b57cec5SDimitry Andric MCInst TLSDescCall;
26170b57cec5SDimitry Andric TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
26180b57cec5SDimitry Andric TLSDescCall.addOperand(Sym);
26190b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TLSDescCall);
26200b57cec5SDimitry Andric
26210b57cec5SDimitry Andric MCInst Blr;
26220b57cec5SDimitry Andric Blr.setOpcode(AArch64::BLR);
26230b57cec5SDimitry Andric Blr.addOperand(MCOperand::createReg(AArch64::X1));
26240b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, Blr);
26250b57cec5SDimitry Andric
26260b57cec5SDimitry Andric return;
26270b57cec5SDimitry Andric }
26280b57cec5SDimitry Andric
2629e8d8bef9SDimitry Andric case AArch64::JumpTableDest32:
26300b57cec5SDimitry Andric case AArch64::JumpTableDest16:
26310b57cec5SDimitry Andric case AArch64::JumpTableDest8:
2632e8d8bef9SDimitry Andric LowerJumpTableDest(*OutStreamer, *MI);
26330b57cec5SDimitry Andric return;
26340b57cec5SDimitry Andric
26350fca6ea1SDimitry Andric case AArch64::BR_JumpTable:
26360fca6ea1SDimitry Andric LowerHardenedBRJumpTable(*MI);
26370fca6ea1SDimitry Andric return;
26380fca6ea1SDimitry Andric
26390b57cec5SDimitry Andric case AArch64::FMOVH0:
26400b57cec5SDimitry Andric case AArch64::FMOVS0:
26410b57cec5SDimitry Andric case AArch64::FMOVD0:
2642fe6060f1SDimitry Andric emitFMov0(*MI);
26430b57cec5SDimitry Andric return;
26440b57cec5SDimitry Andric
26451fd87a68SDimitry Andric case AArch64::MOPSMemoryCopyPseudo:
26461fd87a68SDimitry Andric case AArch64::MOPSMemoryMovePseudo:
26471fd87a68SDimitry Andric case AArch64::MOPSMemorySetPseudo:
26481fd87a68SDimitry Andric case AArch64::MOPSMemorySetTaggingPseudo:
26491fd87a68SDimitry Andric LowerMOPS(*OutStreamer, *MI);
26501fd87a68SDimitry Andric return;
26511fd87a68SDimitry Andric
26520b57cec5SDimitry Andric case TargetOpcode::STACKMAP:
26530b57cec5SDimitry Andric return LowerSTACKMAP(*OutStreamer, SM, *MI);
26540b57cec5SDimitry Andric
26550b57cec5SDimitry Andric case TargetOpcode::PATCHPOINT:
26560b57cec5SDimitry Andric return LowerPATCHPOINT(*OutStreamer, SM, *MI);
26570b57cec5SDimitry Andric
2658e8d8bef9SDimitry Andric case TargetOpcode::STATEPOINT:
2659e8d8bef9SDimitry Andric return LowerSTATEPOINT(*OutStreamer, SM, *MI);
2660e8d8bef9SDimitry Andric
2661e8d8bef9SDimitry Andric case TargetOpcode::FAULTING_OP:
2662e8d8bef9SDimitry Andric return LowerFAULTING_OP(*MI);
2663e8d8bef9SDimitry Andric
26640b57cec5SDimitry Andric case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
26650b57cec5SDimitry Andric LowerPATCHABLE_FUNCTION_ENTER(*MI);
26660b57cec5SDimitry Andric return;
26670b57cec5SDimitry Andric
26680b57cec5SDimitry Andric case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
26690b57cec5SDimitry Andric LowerPATCHABLE_FUNCTION_EXIT(*MI);
26700b57cec5SDimitry Andric return;
26710b57cec5SDimitry Andric
26720b57cec5SDimitry Andric case TargetOpcode::PATCHABLE_TAIL_CALL:
26730b57cec5SDimitry Andric LowerPATCHABLE_TAIL_CALL(*MI);
26740b57cec5SDimitry Andric return;
267506c3fb27SDimitry Andric case TargetOpcode::PATCHABLE_EVENT_CALL:
267606c3fb27SDimitry Andric return LowerPATCHABLE_EVENT_CALL(*MI, false);
267706c3fb27SDimitry Andric case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
267806c3fb27SDimitry Andric return LowerPATCHABLE_EVENT_CALL(*MI, true);
26790b57cec5SDimitry Andric
2680bdd1243dSDimitry Andric case AArch64::KCFI_CHECK:
2681bdd1243dSDimitry Andric LowerKCFI_CHECK(*MI);
2682bdd1243dSDimitry Andric return;
2683bdd1243dSDimitry Andric
26840b57cec5SDimitry Andric case AArch64::HWASAN_CHECK_MEMACCESS:
26858bcb0991SDimitry Andric case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
26860fca6ea1SDimitry Andric case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
26870fca6ea1SDimitry Andric case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
26880b57cec5SDimitry Andric LowerHWASAN_CHECK_MEMACCESS(*MI);
26890b57cec5SDimitry Andric return;
26900b57cec5SDimitry Andric
26910b57cec5SDimitry Andric case AArch64::SEH_StackAlloc:
2692fe6060f1SDimitry Andric TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
26930b57cec5SDimitry Andric return;
26940b57cec5SDimitry Andric
26950b57cec5SDimitry Andric case AArch64::SEH_SaveFPLR:
2696fe6060f1SDimitry Andric TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
26970b57cec5SDimitry Andric return;
26980b57cec5SDimitry Andric
26990b57cec5SDimitry Andric case AArch64::SEH_SaveFPLR_X:
27000b57cec5SDimitry Andric assert(MI->getOperand(0).getImm() < 0 &&
27010b57cec5SDimitry Andric "Pre increment SEH opcode must have a negative offset");
2702fe6060f1SDimitry Andric TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
27030b57cec5SDimitry Andric return;
27040b57cec5SDimitry Andric
27050b57cec5SDimitry Andric case AArch64::SEH_SaveReg:
2706fe6060f1SDimitry Andric TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
27070b57cec5SDimitry Andric MI->getOperand(1).getImm());
27080b57cec5SDimitry Andric return;
27090b57cec5SDimitry Andric
27100b57cec5SDimitry Andric case AArch64::SEH_SaveReg_X:
27110b57cec5SDimitry Andric assert(MI->getOperand(1).getImm() < 0 &&
27120b57cec5SDimitry Andric "Pre increment SEH opcode must have a negative offset");
2713fe6060f1SDimitry Andric TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
27140b57cec5SDimitry Andric -MI->getOperand(1).getImm());
27150b57cec5SDimitry Andric return;
27160b57cec5SDimitry Andric
27170b57cec5SDimitry Andric case AArch64::SEH_SaveRegP:
2718e8d8bef9SDimitry Andric if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 &&
2719e8d8bef9SDimitry Andric MI->getOperand(0).getImm() <= 28) {
2720e8d8bef9SDimitry Andric assert((MI->getOperand(0).getImm() - 19) % 2 == 0 &&
2721e8d8bef9SDimitry Andric "Register paired with LR must be odd");
2722fe6060f1SDimitry Andric TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(),
2723e8d8bef9SDimitry Andric MI->getOperand(2).getImm());
2724e8d8bef9SDimitry Andric return;
2725e8d8bef9SDimitry Andric }
27260b57cec5SDimitry Andric assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
27270b57cec5SDimitry Andric "Non-consecutive registers not allowed for save_regp");
2728fe6060f1SDimitry Andric TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
27290b57cec5SDimitry Andric MI->getOperand(2).getImm());
27300b57cec5SDimitry Andric return;
27310b57cec5SDimitry Andric
27320b57cec5SDimitry Andric case AArch64::SEH_SaveRegP_X:
27330b57cec5SDimitry Andric assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
27340b57cec5SDimitry Andric "Non-consecutive registers not allowed for save_regp_x");
27350b57cec5SDimitry Andric assert(MI->getOperand(2).getImm() < 0 &&
27360b57cec5SDimitry Andric "Pre increment SEH opcode must have a negative offset");
2737fe6060f1SDimitry Andric TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
27380b57cec5SDimitry Andric -MI->getOperand(2).getImm());
27390b57cec5SDimitry Andric return;
27400b57cec5SDimitry Andric
27410b57cec5SDimitry Andric case AArch64::SEH_SaveFReg:
2742fe6060f1SDimitry Andric TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
27430b57cec5SDimitry Andric MI->getOperand(1).getImm());
27440b57cec5SDimitry Andric return;
27450b57cec5SDimitry Andric
27460b57cec5SDimitry Andric case AArch64::SEH_SaveFReg_X:
27470b57cec5SDimitry Andric assert(MI->getOperand(1).getImm() < 0 &&
27480b57cec5SDimitry Andric "Pre increment SEH opcode must have a negative offset");
2749fe6060f1SDimitry Andric TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
27500b57cec5SDimitry Andric -MI->getOperand(1).getImm());
27510b57cec5SDimitry Andric return;
27520b57cec5SDimitry Andric
27530b57cec5SDimitry Andric case AArch64::SEH_SaveFRegP:
27540b57cec5SDimitry Andric assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
27550b57cec5SDimitry Andric "Non-consecutive registers not allowed for save_regp");
2756fe6060f1SDimitry Andric TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
27570b57cec5SDimitry Andric MI->getOperand(2).getImm());
27580b57cec5SDimitry Andric return;
27590b57cec5SDimitry Andric
27600b57cec5SDimitry Andric case AArch64::SEH_SaveFRegP_X:
27610b57cec5SDimitry Andric assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
27620b57cec5SDimitry Andric "Non-consecutive registers not allowed for save_regp_x");
27630b57cec5SDimitry Andric assert(MI->getOperand(2).getImm() < 0 &&
27640b57cec5SDimitry Andric "Pre increment SEH opcode must have a negative offset");
2765fe6060f1SDimitry Andric TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
27660b57cec5SDimitry Andric -MI->getOperand(2).getImm());
27670b57cec5SDimitry Andric return;
27680b57cec5SDimitry Andric
27690b57cec5SDimitry Andric case AArch64::SEH_SetFP:
2770fe6060f1SDimitry Andric TS->emitARM64WinCFISetFP();
27710b57cec5SDimitry Andric return;
27720b57cec5SDimitry Andric
27730b57cec5SDimitry Andric case AArch64::SEH_AddFP:
2774fe6060f1SDimitry Andric TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm());
27750b57cec5SDimitry Andric return;
27760b57cec5SDimitry Andric
27770b57cec5SDimitry Andric case AArch64::SEH_Nop:
2778fe6060f1SDimitry Andric TS->emitARM64WinCFINop();
27790b57cec5SDimitry Andric return;
27800b57cec5SDimitry Andric
27810b57cec5SDimitry Andric case AArch64::SEH_PrologEnd:
2782fe6060f1SDimitry Andric TS->emitARM64WinCFIPrologEnd();
27830b57cec5SDimitry Andric return;
27840b57cec5SDimitry Andric
27850b57cec5SDimitry Andric case AArch64::SEH_EpilogStart:
2786fe6060f1SDimitry Andric TS->emitARM64WinCFIEpilogStart();
27870b57cec5SDimitry Andric return;
27880b57cec5SDimitry Andric
27890b57cec5SDimitry Andric case AArch64::SEH_EpilogEnd:
2790fe6060f1SDimitry Andric TS->emitARM64WinCFIEpilogEnd();
27910b57cec5SDimitry Andric return;
2792bdd1243dSDimitry Andric
2793bdd1243dSDimitry Andric case AArch64::SEH_PACSignLR:
2794bdd1243dSDimitry Andric TS->emitARM64WinCFIPACSignLR();
2795bdd1243dSDimitry Andric return;
27967a6dacacSDimitry Andric
27977a6dacacSDimitry Andric case AArch64::SEH_SaveAnyRegQP:
27987a6dacacSDimitry Andric assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
27997a6dacacSDimitry Andric "Non-consecutive registers not allowed for save_any_reg");
28007a6dacacSDimitry Andric assert(MI->getOperand(2).getImm() >= 0 &&
28017a6dacacSDimitry Andric "SaveAnyRegQP SEH opcode offset must be non-negative");
28027a6dacacSDimitry Andric assert(MI->getOperand(2).getImm() <= 1008 &&
28037a6dacacSDimitry Andric "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
28047a6dacacSDimitry Andric TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(),
28057a6dacacSDimitry Andric MI->getOperand(2).getImm());
28067a6dacacSDimitry Andric return;
28077a6dacacSDimitry Andric
28087a6dacacSDimitry Andric case AArch64::SEH_SaveAnyRegQPX:
28097a6dacacSDimitry Andric assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
28107a6dacacSDimitry Andric "Non-consecutive registers not allowed for save_any_reg");
28117a6dacacSDimitry Andric assert(MI->getOperand(2).getImm() < 0 &&
28127a6dacacSDimitry Andric "SaveAnyRegQPX SEH opcode offset must be negative");
28137a6dacacSDimitry Andric assert(MI->getOperand(2).getImm() >= -1008 &&
28147a6dacacSDimitry Andric "SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
28157a6dacacSDimitry Andric TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(),
28167a6dacacSDimitry Andric -MI->getOperand(2).getImm());
28177a6dacacSDimitry Andric return;
28180b57cec5SDimitry Andric }
28190b57cec5SDimitry Andric
28200b57cec5SDimitry Andric // Finally, do the automated lowerings for everything else.
28210b57cec5SDimitry Andric MCInst TmpInst;
28220b57cec5SDimitry Andric MCInstLowering.Lower(MI, TmpInst);
28230b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
28240b57cec5SDimitry Andric }
28250b57cec5SDimitry Andric
emitMachOIFuncStubBody(Module & M,const GlobalIFunc & GI,MCSymbol * LazyPointer)28265f757f3fSDimitry Andric void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
28275f757f3fSDimitry Andric MCSymbol *LazyPointer) {
28285f757f3fSDimitry Andric // _ifunc:
28295f757f3fSDimitry Andric // adrp x16, lazy_pointer@GOTPAGE
28305f757f3fSDimitry Andric // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
28315f757f3fSDimitry Andric // ldr x16, [x16]
28325f757f3fSDimitry Andric // br x16
28335f757f3fSDimitry Andric
28345f757f3fSDimitry Andric {
28355f757f3fSDimitry Andric MCInst Adrp;
28365f757f3fSDimitry Andric Adrp.setOpcode(AArch64::ADRP);
28375f757f3fSDimitry Andric Adrp.addOperand(MCOperand::createReg(AArch64::X16));
28385f757f3fSDimitry Andric MCOperand SymPage;
28395f757f3fSDimitry Andric MCInstLowering.lowerOperand(
28405f757f3fSDimitry Andric MachineOperand::CreateMCSymbol(LazyPointer,
28415f757f3fSDimitry Andric AArch64II::MO_GOT | AArch64II::MO_PAGE),
28425f757f3fSDimitry Andric SymPage);
28435f757f3fSDimitry Andric Adrp.addOperand(SymPage);
28445f757f3fSDimitry Andric OutStreamer->emitInstruction(Adrp, *STI);
28455f757f3fSDimitry Andric }
28465f757f3fSDimitry Andric
28475f757f3fSDimitry Andric {
28485f757f3fSDimitry Andric MCInst Ldr;
28495f757f3fSDimitry Andric Ldr.setOpcode(AArch64::LDRXui);
28505f757f3fSDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::X16));
28515f757f3fSDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::X16));
28525f757f3fSDimitry Andric MCOperand SymPageOff;
28535f757f3fSDimitry Andric MCInstLowering.lowerOperand(
28545f757f3fSDimitry Andric MachineOperand::CreateMCSymbol(LazyPointer, AArch64II::MO_GOT |
28555f757f3fSDimitry Andric AArch64II::MO_PAGEOFF),
28565f757f3fSDimitry Andric SymPageOff);
28575f757f3fSDimitry Andric Ldr.addOperand(SymPageOff);
28585f757f3fSDimitry Andric Ldr.addOperand(MCOperand::createImm(0));
28595f757f3fSDimitry Andric OutStreamer->emitInstruction(Ldr, *STI);
28605f757f3fSDimitry Andric }
28615f757f3fSDimitry Andric
28625f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
28635f757f3fSDimitry Andric .addReg(AArch64::X16)
28645f757f3fSDimitry Andric .addReg(AArch64::X16)
28655f757f3fSDimitry Andric .addImm(0),
28665f757f3fSDimitry Andric *STI);
28675f757f3fSDimitry Andric
28685f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
28695f757f3fSDimitry Andric ? AArch64::BRAAZ
28705f757f3fSDimitry Andric : AArch64::BR)
28715f757f3fSDimitry Andric .addReg(AArch64::X16),
28725f757f3fSDimitry Andric *STI);
28735f757f3fSDimitry Andric }
28745f757f3fSDimitry Andric
emitMachOIFuncStubHelperBody(Module & M,const GlobalIFunc & GI,MCSymbol * LazyPointer)28755f757f3fSDimitry Andric void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
28765f757f3fSDimitry Andric const GlobalIFunc &GI,
28775f757f3fSDimitry Andric MCSymbol *LazyPointer) {
28785f757f3fSDimitry Andric // These stub helpers are only ever called once, so here we're optimizing for
28795f757f3fSDimitry Andric // minimum size by using the pre-indexed store variants, which saves a few
28805f757f3fSDimitry Andric // bytes of instructions to bump & restore sp.
28815f757f3fSDimitry Andric
28825f757f3fSDimitry Andric // _ifunc.stub_helper:
28835f757f3fSDimitry Andric // stp fp, lr, [sp, #-16]!
28845f757f3fSDimitry Andric // mov fp, sp
28855f757f3fSDimitry Andric // stp x1, x0, [sp, #-16]!
28865f757f3fSDimitry Andric // stp x3, x2, [sp, #-16]!
28875f757f3fSDimitry Andric // stp x5, x4, [sp, #-16]!
28885f757f3fSDimitry Andric // stp x7, x6, [sp, #-16]!
28895f757f3fSDimitry Andric // stp d1, d0, [sp, #-16]!
28905f757f3fSDimitry Andric // stp d3, d2, [sp, #-16]!
28915f757f3fSDimitry Andric // stp d5, d4, [sp, #-16]!
28925f757f3fSDimitry Andric // stp d7, d6, [sp, #-16]!
28935f757f3fSDimitry Andric // bl _resolver
28945f757f3fSDimitry Andric // adrp x16, lazy_pointer@GOTPAGE
28955f757f3fSDimitry Andric // ldr x16, [x16, lazy_pointer@GOTPAGEOFF]
28965f757f3fSDimitry Andric // str x0, [x16]
28975f757f3fSDimitry Andric // mov x16, x0
28985f757f3fSDimitry Andric // ldp d7, d6, [sp], #16
28995f757f3fSDimitry Andric // ldp d5, d4, [sp], #16
29005f757f3fSDimitry Andric // ldp d3, d2, [sp], #16
29015f757f3fSDimitry Andric // ldp d1, d0, [sp], #16
29025f757f3fSDimitry Andric // ldp x7, x6, [sp], #16
29035f757f3fSDimitry Andric // ldp x5, x4, [sp], #16
29045f757f3fSDimitry Andric // ldp x3, x2, [sp], #16
29055f757f3fSDimitry Andric // ldp x1, x0, [sp], #16
29065f757f3fSDimitry Andric // ldp fp, lr, [sp], #16
29075f757f3fSDimitry Andric // br x16
29085f757f3fSDimitry Andric
29095f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
29105f757f3fSDimitry Andric .addReg(AArch64::SP)
29115f757f3fSDimitry Andric .addReg(AArch64::FP)
29125f757f3fSDimitry Andric .addReg(AArch64::LR)
29135f757f3fSDimitry Andric .addReg(AArch64::SP)
29145f757f3fSDimitry Andric .addImm(-2),
29155f757f3fSDimitry Andric *STI);
29165f757f3fSDimitry Andric
29175f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
29185f757f3fSDimitry Andric .addReg(AArch64::FP)
29195f757f3fSDimitry Andric .addReg(AArch64::SP)
29205f757f3fSDimitry Andric .addImm(0)
29215f757f3fSDimitry Andric .addImm(0),
29225f757f3fSDimitry Andric *STI);
29235f757f3fSDimitry Andric
29245f757f3fSDimitry Andric for (int I = 0; I != 4; ++I)
29255f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
29265f757f3fSDimitry Andric .addReg(AArch64::SP)
29275f757f3fSDimitry Andric .addReg(AArch64::X1 + 2 * I)
29285f757f3fSDimitry Andric .addReg(AArch64::X0 + 2 * I)
29295f757f3fSDimitry Andric .addReg(AArch64::SP)
29305f757f3fSDimitry Andric .addImm(-2),
29315f757f3fSDimitry Andric *STI);
29325f757f3fSDimitry Andric
29335f757f3fSDimitry Andric for (int I = 0; I != 4; ++I)
29345f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
29355f757f3fSDimitry Andric .addReg(AArch64::SP)
29365f757f3fSDimitry Andric .addReg(AArch64::D1 + 2 * I)
29375f757f3fSDimitry Andric .addReg(AArch64::D0 + 2 * I)
29385f757f3fSDimitry Andric .addReg(AArch64::SP)
29395f757f3fSDimitry Andric .addImm(-2),
29405f757f3fSDimitry Andric *STI);
29415f757f3fSDimitry Andric
29425f757f3fSDimitry Andric OutStreamer->emitInstruction(
29435f757f3fSDimitry Andric MCInstBuilder(AArch64::BL)
29445f757f3fSDimitry Andric .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
29455f757f3fSDimitry Andric *STI);
29465f757f3fSDimitry Andric
29475f757f3fSDimitry Andric {
29485f757f3fSDimitry Andric MCInst Adrp;
29495f757f3fSDimitry Andric Adrp.setOpcode(AArch64::ADRP);
29505f757f3fSDimitry Andric Adrp.addOperand(MCOperand::createReg(AArch64::X16));
29515f757f3fSDimitry Andric MCOperand SymPage;
29525f757f3fSDimitry Andric MCInstLowering.lowerOperand(
29535f757f3fSDimitry Andric MachineOperand::CreateES(LazyPointer->getName().data() + 1,
29545f757f3fSDimitry Andric AArch64II::MO_GOT | AArch64II::MO_PAGE),
29555f757f3fSDimitry Andric SymPage);
29565f757f3fSDimitry Andric Adrp.addOperand(SymPage);
29575f757f3fSDimitry Andric OutStreamer->emitInstruction(Adrp, *STI);
29585f757f3fSDimitry Andric }
29595f757f3fSDimitry Andric
29605f757f3fSDimitry Andric {
29615f757f3fSDimitry Andric MCInst Ldr;
29625f757f3fSDimitry Andric Ldr.setOpcode(AArch64::LDRXui);
29635f757f3fSDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::X16));
29645f757f3fSDimitry Andric Ldr.addOperand(MCOperand::createReg(AArch64::X16));
29655f757f3fSDimitry Andric MCOperand SymPageOff;
29665f757f3fSDimitry Andric MCInstLowering.lowerOperand(
29675f757f3fSDimitry Andric MachineOperand::CreateES(LazyPointer->getName().data() + 1,
29685f757f3fSDimitry Andric AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
29695f757f3fSDimitry Andric SymPageOff);
29705f757f3fSDimitry Andric Ldr.addOperand(SymPageOff);
29715f757f3fSDimitry Andric Ldr.addOperand(MCOperand::createImm(0));
29725f757f3fSDimitry Andric OutStreamer->emitInstruction(Ldr, *STI);
29735f757f3fSDimitry Andric }
29745f757f3fSDimitry Andric
29755f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
29765f757f3fSDimitry Andric .addReg(AArch64::X0)
29775f757f3fSDimitry Andric .addReg(AArch64::X16)
29785f757f3fSDimitry Andric .addImm(0),
29795f757f3fSDimitry Andric *STI);
29805f757f3fSDimitry Andric
29815f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
29825f757f3fSDimitry Andric .addReg(AArch64::X16)
29835f757f3fSDimitry Andric .addReg(AArch64::X0)
29845f757f3fSDimitry Andric .addImm(0)
29855f757f3fSDimitry Andric .addImm(0),
29865f757f3fSDimitry Andric *STI);
29875f757f3fSDimitry Andric
29885f757f3fSDimitry Andric for (int I = 3; I != -1; --I)
29895f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
29905f757f3fSDimitry Andric .addReg(AArch64::SP)
29915f757f3fSDimitry Andric .addReg(AArch64::D1 + 2 * I)
29925f757f3fSDimitry Andric .addReg(AArch64::D0 + 2 * I)
29935f757f3fSDimitry Andric .addReg(AArch64::SP)
29945f757f3fSDimitry Andric .addImm(2),
29955f757f3fSDimitry Andric *STI);
29965f757f3fSDimitry Andric
29975f757f3fSDimitry Andric for (int I = 3; I != -1; --I)
29985f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
29995f757f3fSDimitry Andric .addReg(AArch64::SP)
30005f757f3fSDimitry Andric .addReg(AArch64::X1 + 2 * I)
30015f757f3fSDimitry Andric .addReg(AArch64::X0 + 2 * I)
30025f757f3fSDimitry Andric .addReg(AArch64::SP)
30035f757f3fSDimitry Andric .addImm(2),
30045f757f3fSDimitry Andric *STI);
30055f757f3fSDimitry Andric
30065f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
30075f757f3fSDimitry Andric .addReg(AArch64::SP)
30085f757f3fSDimitry Andric .addReg(AArch64::FP)
30095f757f3fSDimitry Andric .addReg(AArch64::LR)
30105f757f3fSDimitry Andric .addReg(AArch64::SP)
30115f757f3fSDimitry Andric .addImm(2),
30125f757f3fSDimitry Andric *STI);
30135f757f3fSDimitry Andric
30145f757f3fSDimitry Andric OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
30155f757f3fSDimitry Andric ? AArch64::BRAAZ
30165f757f3fSDimitry Andric : AArch64::BR)
30175f757f3fSDimitry Andric .addReg(AArch64::X16),
30185f757f3fSDimitry Andric *STI);
30195f757f3fSDimitry Andric }
30205f757f3fSDimitry Andric
lowerConstant(const Constant * CV)30217a6dacacSDimitry Andric const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV) {
30227a6dacacSDimitry Andric if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
30237a6dacacSDimitry Andric return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0),
30247a6dacacSDimitry Andric OutContext);
30257a6dacacSDimitry Andric }
30267a6dacacSDimitry Andric
30277a6dacacSDimitry Andric return AsmPrinter::lowerConstant(CV);
30287a6dacacSDimitry Andric }
30297a6dacacSDimitry Andric
30300b57cec5SDimitry Andric // Force static initialization.
LLVMInitializeAArch64AsmPrinter()3031480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() {
30320b57cec5SDimitry Andric RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
30330b57cec5SDimitry Andric RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget());
30340b57cec5SDimitry Andric RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target());
30358bcb0991SDimitry Andric RegisterAsmPrinter<AArch64AsmPrinter> W(getTheARM64_32Target());
30368bcb0991SDimitry Andric RegisterAsmPrinter<AArch64AsmPrinter> V(getTheAArch64_32Target());
30370b57cec5SDimitry Andric }
3038