| //===--- AArch64Subtarget.h - Define Subtarget for the AArch64 -*- C++ -*--===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file declares the AArch64 specific subclass of TargetSubtarget. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64SUBTARGET_H | |
| #define LLVM_LIB_TARGET_AARCH64_AARCH64SUBTARGET_H | |
| #include "AArch64FrameLowering.h" | |
| #include "AArch64ISelLowering.h" | |
| #include "AArch64InstrInfo.h" | |
| #include "AArch64RegisterInfo.h" | |
| #include "AArch64SelectionDAGInfo.h" | |
| #include "llvm/CodeGen/GlobalISel/CallLowering.h" | |
| #include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h" | |
| #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" | |
| #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" | |
| #include "llvm/CodeGen/RegisterBankInfo.h" | |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | |
| #include "llvm/IR/DataLayout.h" | |
| #include <string> | |
| #define GET_SUBTARGETINFO_HEADER | |
| #include "AArch64GenSubtargetInfo.inc" | |
| namespace llvm { | |
| class GlobalValue; | |
| class StringRef; | |
| class Triple; | |
| class AArch64Subtarget final : public AArch64GenSubtargetInfo { | |
| public: | |
| enum ARMProcFamilyEnum : uint8_t { | |
| Others, | |
| A64FX, | |
| Ampere1, | |
| Ampere1A, | |
| AppleA7, | |
| AppleA10, | |
| AppleA11, | |
| AppleA12, | |
| AppleA13, | |
| AppleA14, | |
| AppleA15, | |
| AppleA16, | |
| Carmel, | |
| CortexA35, | |
| CortexA53, | |
| CortexA55, | |
| CortexA510, | |
| CortexA57, | |
| CortexA65, | |
| CortexA72, | |
| CortexA73, | |
| CortexA75, | |
| CortexA76, | |
| CortexA77, | |
| CortexA78, | |
| CortexA78C, | |
| CortexA710, | |
| CortexA715, | |
| CortexR82, | |
| CortexX1, | |
| CortexX1C, | |
| CortexX2, | |
| CortexX3, | |
| ExynosM3, | |
| Falkor, | |
| Kryo, | |
| NeoverseE1, | |
| NeoverseN1, | |
| NeoverseN2, | |
| Neoverse512TVB, | |
| NeoverseV1, | |
| NeoverseV2, | |
| Saphira, | |
| ThunderX2T99, | |
| ThunderX, | |
| ThunderXT81, | |
| ThunderXT83, | |
| ThunderXT88, | |
| ThunderX3T110, | |
| TSV110 | |
| }; | |
| protected: | |
| /// ARMProcFamily - ARM processor family: Cortex-A53, Cortex-A57, and others. | |
| ARMProcFamilyEnum ARMProcFamily = Others; | |
| // Enable 64-bit vectorization in SLP. | |
| unsigned MinVectorRegisterBitWidth = 64; | |
| // Bool members corresponding to the SubtargetFeatures defined in tablegen | |
| #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ | |
| bool ATTRIBUTE = DEFAULT; | |
| #include "AArch64GenSubtargetInfo.inc" | |
| uint8_t MaxInterleaveFactor = 2; | |
| uint8_t VectorInsertExtractBaseCost = 3; | |
| uint16_t CacheLineSize = 0; | |
| uint16_t PrefetchDistance = 0; | |
| uint16_t MinPrefetchStride = 1; | |
| unsigned MaxPrefetchIterationsAhead = UINT_MAX; | |
| unsigned PrefFunctionLogAlignment = 0; | |
| unsigned PrefLoopLogAlignment = 0; | |
| unsigned MaxBytesForLoopAlignment = 0; | |
| unsigned MaxJumpTableSize = 0; | |
| // ReserveXRegister[i] - X#i is not available as a general purpose register. | |
| BitVector ReserveXRegister; | |
| // ReserveXRegisterForRA[i] - X#i is not available for register allocator. | |
| BitVector ReserveXRegisterForRA; | |
| // CustomCallUsedXRegister[i] - X#i call saved. | |
| BitVector CustomCallSavedXRegs; | |
| bool IsLittle; | |
| bool StreamingSVEModeDisabled; | |
| unsigned MinSVEVectorSizeInBits; | |
| unsigned MaxSVEVectorSizeInBits; | |
| unsigned VScaleForTuning = 2; | |
| /// TargetTriple - What processor and OS we're targeting. | |
| Triple TargetTriple; | |
| AArch64FrameLowering FrameLowering; | |
| AArch64InstrInfo InstrInfo; | |
| AArch64SelectionDAGInfo TSInfo; | |
| AArch64TargetLowering TLInfo; | |
| /// GlobalISel related APIs. | |
| std::unique_ptr<CallLowering> CallLoweringInfo; | |
| std::unique_ptr<InlineAsmLowering> InlineAsmLoweringInfo; | |
| std::unique_ptr<InstructionSelector> InstSelector; | |
| std::unique_ptr<LegalizerInfo> Legalizer; | |
| std::unique_ptr<RegisterBankInfo> RegBankInfo; | |
| private: | |
| /// initializeSubtargetDependencies - Initializes using CPUString and the | |
| /// passed in feature string so that we can use initializer lists for | |
| /// subtarget initialization. | |
| AArch64Subtarget &initializeSubtargetDependencies(StringRef FS, | |
| StringRef CPUString, | |
| StringRef TuneCPUString); | |
| /// Initialize properties based on the selected processor family. | |
| void initializeProperties(); | |
| public: | |
| /// This constructor initializes the data members to match that | |
| /// of the specified triple. | |
| AArch64Subtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, | |
| StringRef FS, const TargetMachine &TM, bool LittleEndian, | |
| unsigned MinSVEVectorSizeInBitsOverride = 0, | |
| unsigned MaxSVEVectorSizeInBitsOverride = 0, | |
| bool StreamingSVEModeDisabled = true); | |
| // Getters for SubtargetFeatures defined in tablegen | |
| #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ | |
| bool GETTER() const { return ATTRIBUTE; } | |
| #include "AArch64GenSubtargetInfo.inc" | |
| const AArch64SelectionDAGInfo *getSelectionDAGInfo() const override { | |
| return &TSInfo; | |
| } | |
| const AArch64FrameLowering *getFrameLowering() const override { | |
| return &FrameLowering; | |
| } | |
| const AArch64TargetLowering *getTargetLowering() const override { | |
| return &TLInfo; | |
| } | |
| const AArch64InstrInfo *getInstrInfo() const override { return &InstrInfo; } | |
| const AArch64RegisterInfo *getRegisterInfo() const override { | |
| return &getInstrInfo()->getRegisterInfo(); | |
| } | |
| const CallLowering *getCallLowering() const override; | |
| const InlineAsmLowering *getInlineAsmLowering() const override; | |
| InstructionSelector *getInstructionSelector() const override; | |
| const LegalizerInfo *getLegalizerInfo() const override; | |
| const RegisterBankInfo *getRegBankInfo() const override; | |
| const Triple &getTargetTriple() const { return TargetTriple; } | |
| bool enableMachineScheduler() const override { return true; } | |
| bool enablePostRAScheduler() const override { return usePostRAScheduler(); } | |
| /// Returns ARM processor family. | |
| /// Avoid this function! CPU specifics should be kept local to this class | |
| /// and preferably modeled with SubtargetFeatures or properties in | |
| /// initializeProperties(). | |
| ARMProcFamilyEnum getProcFamily() const { | |
| return ARMProcFamily; | |
| } | |
| bool isXRaySupported() const override { return true; } | |
| unsigned getMinVectorRegisterBitWidth() const { | |
| // Don't assume any minimum vector size when PSTATE.SM may not be 0. | |
| if (!isStreamingSVEModeDisabled()) | |
| return 0; | |
| return MinVectorRegisterBitWidth; | |
| } | |
| bool isXRegisterReserved(size_t i) const { return ReserveXRegister[i]; } | |
| bool isXRegisterReservedForRA(size_t i) const { return ReserveXRegisterForRA[i]; } | |
| unsigned getNumXRegisterReserved() const { | |
| BitVector AllReservedX(AArch64::GPR64commonRegClass.getNumRegs()); | |
| AllReservedX |= ReserveXRegister; | |
| AllReservedX |= ReserveXRegisterForRA; | |
| return AllReservedX.count(); | |
| } | |
| bool isXRegCustomCalleeSaved(size_t i) const { | |
| return CustomCallSavedXRegs[i]; | |
| } | |
| bool hasCustomCallingConv() const { return CustomCallSavedXRegs.any(); } | |
| /// Return true if the CPU supports any kind of instruction fusion. | |
| bool hasFusion() const { | |
| return hasArithmeticBccFusion() || hasArithmeticCbzFusion() || | |
| hasFuseAES() || hasFuseArithmeticLogic() || hasFuseCCSelect() || | |
| hasFuseAdrpAdd() || hasFuseLiterals(); | |
| } | |
| unsigned getMaxInterleaveFactor() const { return MaxInterleaveFactor; } | |
| unsigned getVectorInsertExtractBaseCost() const; | |
| unsigned getCacheLineSize() const override { return CacheLineSize; } | |
| unsigned getPrefetchDistance() const override { return PrefetchDistance; } | |
| unsigned getMinPrefetchStride(unsigned NumMemAccesses, | |
| unsigned NumStridedMemAccesses, | |
| unsigned NumPrefetches, | |
| bool HasCall) const override { | |
| return MinPrefetchStride; | |
| } | |
| unsigned getMaxPrefetchIterationsAhead() const override { | |
| return MaxPrefetchIterationsAhead; | |
| } | |
| unsigned getPrefFunctionLogAlignment() const { | |
| return PrefFunctionLogAlignment; | |
| } | |
| unsigned getPrefLoopLogAlignment() const { return PrefLoopLogAlignment; } | |
| unsigned getMaxBytesForLoopAlignment() const { | |
| return MaxBytesForLoopAlignment; | |
| } | |
| unsigned getMaximumJumpTableSize() const { return MaxJumpTableSize; } | |
| /// CPU has TBI (top byte of addresses is ignored during HW address | |
| /// translation) and OS enables it. | |
| bool supportsAddressTopByteIgnored() const; | |
| bool isLittleEndian() const { return IsLittle; } | |
| bool isTargetDarwin() const { return TargetTriple.isOSDarwin(); } | |
| bool isTargetIOS() const { return TargetTriple.isiOS(); } | |
| bool isTargetLinux() const { return TargetTriple.isOSLinux(); } | |
| bool isTargetWindows() const { return TargetTriple.isOSWindows(); } | |
| bool isTargetAndroid() const { return TargetTriple.isAndroid(); } | |
| bool isTargetFuchsia() const { return TargetTriple.isOSFuchsia(); } | |
| bool isWindowsArm64EC() const { return TargetTriple.isWindowsArm64EC(); } | |
| bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); } | |
| bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } | |
| bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); } | |
| bool isTargetILP32() const { | |
| return TargetTriple.isArch32Bit() || | |
| TargetTriple.getEnvironment() == Triple::GNUILP32; | |
| } | |
| bool useAA() const override; | |
| bool addrSinkUsingGEPs() const override { | |
| // Keeping GEPs inbounds is important for exploiting AArch64 | |
| // addressing-modes in ILP32 mode. | |
| return useAA() || isTargetILP32(); | |
| } | |
| bool useSmallAddressing() const { | |
| switch (TLInfo.getTargetMachine().getCodeModel()) { | |
| case CodeModel::Kernel: | |
| // Kernel is currently allowed only for Fuchsia targets, | |
| // where it is the same as Small for almost all purposes. | |
| case CodeModel::Small: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| /// ParseSubtargetFeatures - Parses features string setting specified | |
| /// subtarget options. Definition of function is auto generated by tblgen. | |
| void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); | |
| /// ClassifyGlobalReference - Find the target operand flags that describe | |
| /// how a global value should be referenced for the current subtarget. | |
| unsigned ClassifyGlobalReference(const GlobalValue *GV, | |
| const TargetMachine &TM) const; | |
| unsigned classifyGlobalFunctionReference(const GlobalValue *GV, | |
| const TargetMachine &TM) const; | |
| /// This function is design to compatible with the function def in other | |
| /// targets and escape build error about the virtual function def in base | |
| /// class TargetSubtargetInfo. Updeate me if AArch64 target need to use it. | |
| unsigned char | |
| classifyGlobalFunctionReference(const GlobalValue *GV) const override { | |
| return 0; | |
| } | |
| void overrideSchedPolicy(MachineSchedPolicy &Policy, | |
| unsigned NumRegionInstrs) const override; | |
| bool enableEarlyIfConversion() const override; | |
| std::unique_ptr<PBQPRAConstraint> getCustomPBQPConstraints() const override; | |
| bool isCallingConvWin64(CallingConv::ID CC) const { | |
| switch (CC) { | |
| case CallingConv::C: | |
| case CallingConv::Fast: | |
| case CallingConv::Swift: | |
| return isTargetWindows(); | |
| case CallingConv::Win64: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| /// Return whether FrameLowering should always set the "extended frame | |
| /// present" bit in FP, or set it based on a symbol in the runtime. | |
| bool swiftAsyncContextIsDynamicallySet() const { | |
| // Older OS versions (particularly system unwinders) are confused by the | |
| // Swift extended frame, so when building code that might be run on them we | |
| // must dynamically query the concurrency library to determine whether | |
| // extended frames should be flagged as present. | |
| const Triple &TT = getTargetTriple(); | |
| unsigned Major = TT.getOSVersion().getMajor(); | |
| switch(TT.getOS()) { | |
| default: | |
| return false; | |
| case Triple::IOS: | |
| case Triple::TvOS: | |
| return Major < 15; | |
| case Triple::WatchOS: | |
| return Major < 8; | |
| case Triple::MacOSX: | |
| case Triple::Darwin: | |
| return Major < 12; | |
| } | |
| } | |
| void mirFileLoaded(MachineFunction &MF) const override; | |
| bool hasSVEorSME() const { return hasSVE() || hasSME(); } | |
| // Return the known range for the bit length of SVE data registers. A value | |
| // of 0 means nothing is known about that particular limit beyong what's | |
| // implied by the architecture. | |
| unsigned getMaxSVEVectorSizeInBits() const { | |
| assert(hasSVEorSME() && | |
| "Tried to get SVE vector length without SVE support!"); | |
| return MaxSVEVectorSizeInBits; | |
| } | |
| unsigned getMinSVEVectorSizeInBits() const { | |
| assert(hasSVEorSME() && | |
| "Tried to get SVE vector length without SVE support!"); | |
| return MinSVEVectorSizeInBits; | |
| } | |
| bool useSVEForFixedLengthVectors() const { | |
| if (forceStreamingCompatibleSVE()) | |
| return true; | |
| // Prefer NEON unless larger SVE registers are available. | |
| return hasSVE() && getMinSVEVectorSizeInBits() >= 256; | |
| } | |
| bool forceStreamingCompatibleSVE() const; | |
| unsigned getVScaleForTuning() const { return VScaleForTuning; } | |
| const char* getChkStkName() const { | |
| if (isWindowsArm64EC()) | |
| return "__chkstk_arm64ec"; | |
| return "__chkstk"; | |
| } | |
| const char* getSecurityCheckCookieName() const { | |
| if (isWindowsArm64EC()) | |
| return "__security_check_cookie_arm64ec"; | |
| return "__security_check_cookie"; | |
| } | |
| bool isStreamingSVEModeDisabled() const { return StreamingSVEModeDisabled; } | |
| }; | |
| } // End llvm namespace | |
| #endif |