| //===-- X86Subtarget.h - Define Subtarget for the X86 ----------*- 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 X86 specific subclass of TargetSubtargetInfo. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIB_TARGET_X86_X86SUBTARGET_H | |
| #define LLVM_LIB_TARGET_X86_X86SUBTARGET_H | |
| #include "X86FrameLowering.h" | |
| #include "X86ISelLowering.h" | |
| #include "X86InstrInfo.h" | |
| #include "X86SelectionDAGInfo.h" | |
| #include "llvm/ADT/Triple.h" | |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | |
| #include "llvm/IR/CallingConv.h" | |
| #include <climits> | |
| #include <memory> | |
| #define GET_SUBTARGETINFO_HEADER | |
| #include "X86GenSubtargetInfo.inc" | |
| namespace llvm { | |
| class CallLowering; | |
| class GlobalValue; | |
| class InstructionSelector; | |
| class LegalizerInfo; | |
| class RegisterBankInfo; | |
| class StringRef; | |
| class TargetMachine; | |
| /// The X86 backend supports a number of different styles of PIC. | |
| /// | |
| namespace PICStyles { | |
| enum class Style { | |
| StubPIC, // Used on i386-darwin in pic mode. | |
| GOT, // Used on 32 bit elf on when in pic mode. | |
| RIPRel, // Used on X86-64 when in pic mode. | |
| None // Set when not in pic mode. | |
| }; | |
| } // end namespace PICStyles | |
| class X86Subtarget final : public X86GenSubtargetInfo { | |
| enum X86SSEEnum { | |
| NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512 | |
| }; | |
| enum X863DNowEnum { | |
| NoThreeDNow, MMX, ThreeDNow, ThreeDNowA | |
| }; | |
| /// Which PIC style to use | |
| PICStyles::Style PICStyle; | |
| const TargetMachine &TM; | |
| /// SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, or none supported. | |
| X86SSEEnum X86SSELevel = NoSSE; | |
| /// MMX, 3DNow, 3DNow Athlon, or none supported. | |
| X863DNowEnum X863DNowLevel = NoThreeDNow; | |
| #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ | |
| bool ATTRIBUTE = DEFAULT; | |
| #include "X86GenSubtargetInfo.inc" | |
| /// The minimum alignment known to hold of the stack frame on | |
| /// entry to the function and which must be maintained by every function. | |
| Align stackAlignment = Align(4); | |
| Align TileConfigAlignment = Align(4); | |
| /// Max. memset / memcpy size that is turned into rep/movs, rep/stos ops. | |
| /// | |
| // FIXME: this is a known good value for Yonah. How about others? | |
| unsigned MaxInlineSizeThreshold = 128; | |
| /// What processor and OS we're targeting. | |
| Triple TargetTriple; | |
| /// GlobalISel related APIs. | |
| std::unique_ptr<CallLowering> CallLoweringInfo; | |
| std::unique_ptr<LegalizerInfo> Legalizer; | |
| std::unique_ptr<RegisterBankInfo> RegBankInfo; | |
| std::unique_ptr<InstructionSelector> InstSelector; | |
| /// Override the stack alignment. | |
| MaybeAlign StackAlignOverride; | |
| /// Preferred vector width from function attribute. | |
| unsigned PreferVectorWidthOverride; | |
| /// Resolved preferred vector width from function attribute and subtarget | |
| /// features. | |
| unsigned PreferVectorWidth = UINT32_MAX; | |
| /// Required vector width from function attribute. | |
| unsigned RequiredVectorWidth; | |
| X86SelectionDAGInfo TSInfo; | |
| // Ordering here is important. X86InstrInfo initializes X86RegisterInfo which | |
| // X86TargetLowering needs. | |
| X86InstrInfo InstrInfo; | |
| X86TargetLowering TLInfo; | |
| X86FrameLowering FrameLowering; | |
| public: | |
| /// This constructor initializes the data members to match that | |
| /// of the specified triple. | |
| /// | |
| X86Subtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS, | |
| const X86TargetMachine &TM, MaybeAlign StackAlignOverride, | |
| unsigned PreferVectorWidthOverride, | |
| unsigned RequiredVectorWidth); | |
| const X86TargetLowering *getTargetLowering() const override { | |
| return &TLInfo; | |
| } | |
| const X86InstrInfo *getInstrInfo() const override { return &InstrInfo; } | |
| const X86FrameLowering *getFrameLowering() const override { | |
| return &FrameLowering; | |
| } | |
| const X86SelectionDAGInfo *getSelectionDAGInfo() const override { | |
| return &TSInfo; | |
| } | |
| const X86RegisterInfo *getRegisterInfo() const override { | |
| return &getInstrInfo()->getRegisterInfo(); | |
| } | |
| unsigned getTileConfigSize() const { return 64; } | |
| Align getTileConfigAlignment() const { return TileConfigAlignment; } | |
| /// Returns the minimum alignment known to hold of the | |
| /// stack frame on entry to the function and which must be maintained by every | |
| /// function for this subtarget. | |
| Align getStackAlignment() const { return stackAlignment; } | |
| /// Returns the maximum memset / memcpy size | |
| /// that still makes it profitable to inline the call. | |
| unsigned getMaxInlineSizeThreshold() const { return MaxInlineSizeThreshold; } | |
| /// ParseSubtargetFeatures - Parses features string setting specified | |
| /// subtarget options. Definition of function is auto generated by tblgen. | |
| void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); | |
| /// Methods used by Global ISel | |
| const CallLowering *getCallLowering() const override; | |
| InstructionSelector *getInstructionSelector() const override; | |
| const LegalizerInfo *getLegalizerInfo() const override; | |
| const RegisterBankInfo *getRegBankInfo() const override; | |
| private: | |
| /// Initialize the full set of dependencies so we can use an initializer | |
| /// list for X86Subtarget. | |
| X86Subtarget &initializeSubtargetDependencies(StringRef CPU, | |
| StringRef TuneCPU, | |
| StringRef FS); | |
| void initSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); | |
| public: | |
| #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ | |
| bool GETTER() const { return ATTRIBUTE; } | |
| #include "X86GenSubtargetInfo.inc" | |
| /// Is this x86_64 with the ILP32 programming model (x32 ABI)? | |
| bool isTarget64BitILP32() const { | |
| return Is64Bit && (TargetTriple.isX32() || TargetTriple.isOSNaCl()); | |
| } | |
| /// Is this x86_64 with the LP64 programming model (standard AMD64, no x32)? | |
| bool isTarget64BitLP64() const { | |
| return Is64Bit && (!TargetTriple.isX32() && !TargetTriple.isOSNaCl()); | |
| } | |
| PICStyles::Style getPICStyle() const { return PICStyle; } | |
| void setPICStyle(PICStyles::Style Style) { PICStyle = Style; } | |
| bool canUseCMPXCHG8B() const { return hasCX8(); } | |
| bool canUseCMPXCHG16B() const { | |
| // CX16 is just the CPUID bit, instruction requires 64-bit mode too. | |
| return hasCX16() && is64Bit(); | |
| } | |
| // SSE codegen depends on cmovs, and all SSE1+ processors support them. | |
| // All 64-bit processors support cmov. | |
| bool canUseCMOV() const { return hasCMOV() || hasSSE1() || is64Bit(); } | |
| bool hasSSE1() const { return X86SSELevel >= SSE1; } | |
| bool hasSSE2() const { return X86SSELevel >= SSE2; } | |
| bool hasSSE3() const { return X86SSELevel >= SSE3; } | |
| bool hasSSSE3() const { return X86SSELevel >= SSSE3; } | |
| bool hasSSE41() const { return X86SSELevel >= SSE41; } | |
| bool hasSSE42() const { return X86SSELevel >= SSE42; } | |
| bool hasAVX() const { return X86SSELevel >= AVX; } | |
| bool hasAVX2() const { return X86SSELevel >= AVX2; } | |
| bool hasAVX512() const { return X86SSELevel >= AVX512; } | |
| bool hasInt256() const { return hasAVX2(); } | |
| bool hasMMX() const { return X863DNowLevel >= MMX; } | |
| bool hasThreeDNow() const { return X863DNowLevel >= ThreeDNow; } | |
| bool hasThreeDNowA() const { return X863DNowLevel >= ThreeDNowA; } | |
| bool hasAnyFMA() const { return hasFMA() || hasFMA4(); } | |
| bool hasPrefetchW() const { | |
| // The PREFETCHW instruction was added with 3DNow but later CPUs gave it | |
| // its own CPUID bit as part of deprecating 3DNow. Intel eventually added | |
| // it and KNL has another that prefetches to L2 cache. We assume the | |
| // L1 version exists if the L2 version does. | |
| return hasThreeDNow() || hasPRFCHW() || hasPREFETCHWT1(); | |
| } | |
| bool hasSSEPrefetch() const { | |
| // We implicitly enable these when we have a write prefix supporting cache | |
| // level OR if we have prfchw, but don't already have a read prefetch from | |
| // 3dnow. | |
| return hasSSE1() || (hasPRFCHW() && !hasThreeDNow()) || hasPREFETCHWT1() || | |
| hasPREFETCHI(); | |
| } | |
| bool canUseLAHFSAHF() const { return hasLAHFSAHF64() || !is64Bit(); } | |
| // These are generic getters that OR together all of the thunk types | |
| // supported by the subtarget. Therefore useIndirectThunk*() will return true | |
| // if any respective thunk feature is enabled. | |
| bool useIndirectThunkCalls() const { | |
| return useRetpolineIndirectCalls() || useLVIControlFlowIntegrity(); | |
| } | |
| bool useIndirectThunkBranches() const { | |
| return useRetpolineIndirectBranches() || useLVIControlFlowIntegrity(); | |
| } | |
| unsigned getPreferVectorWidth() const { return PreferVectorWidth; } | |
| unsigned getRequiredVectorWidth() const { return RequiredVectorWidth; } | |
| // Helper functions to determine when we should allow widening to 512-bit | |
| // during codegen. | |
| // TODO: Currently we're always allowing widening on CPUs without VLX, | |
| // because for many cases we don't have a better option. | |
| bool canExtendTo512DQ() const { | |
| return hasAVX512() && (!hasVLX() || getPreferVectorWidth() >= 512); | |
| } | |
| bool canExtendTo512BW() const { | |
| return hasBWI() && canExtendTo512DQ(); | |
| } | |
| // If there are no 512-bit vectors and we prefer not to use 512-bit registers, | |
| // disable them in the legalizer. | |
| bool useAVX512Regs() const { | |
| return hasAVX512() && (canExtendTo512DQ() || RequiredVectorWidth > 256); | |
| } | |
| bool useLight256BitInstructions() const { | |
| return getPreferVectorWidth() >= 256 || AllowLight256Bit; | |
| } | |
| bool useBWIRegs() const { | |
| return hasBWI() && useAVX512Regs(); | |
| } | |
| bool isXRaySupported() const override { return is64Bit(); } | |
| /// Use clflush if we have SSE2 or we're on x86-64 (even if we asked for | |
| /// no-sse2). There isn't any reason to disable it if the target processor | |
| /// supports it. | |
| bool hasCLFLUSH() const { return hasSSE2() || is64Bit(); } | |
| /// Use mfence if we have SSE2 or we're on x86-64 (even if we asked for | |
| /// no-sse2). There isn't any reason to disable it if the target processor | |
| /// supports it. | |
| bool hasMFence() const { return hasSSE2() || is64Bit(); } | |
| const Triple &getTargetTriple() const { return TargetTriple; } | |
| bool isTargetDarwin() const { return TargetTriple.isOSDarwin(); } | |
| bool isTargetFreeBSD() const { return TargetTriple.isOSFreeBSD(); } | |
| bool isTargetDragonFly() const { return TargetTriple.isOSDragonFly(); } | |
| bool isTargetSolaris() const { return TargetTriple.isOSSolaris(); } | |
| bool isTargetPS() const { return TargetTriple.isPS(); } | |
| bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } | |
| bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); } | |
| bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); } | |
| bool isTargetLinux() const { return TargetTriple.isOSLinux(); } | |
| bool isTargetKFreeBSD() const { return TargetTriple.isOSKFreeBSD(); } | |
| bool isTargetGlibc() const { return TargetTriple.isOSGlibc(); } | |
| bool isTargetAndroid() const { return TargetTriple.isAndroid(); } | |
| bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); } | |
| bool isTargetNaCl32() const { return isTargetNaCl() && !is64Bit(); } | |
| bool isTargetNaCl64() const { return isTargetNaCl() && is64Bit(); } | |
| bool isTargetMCU() const { return TargetTriple.isOSIAMCU(); } | |
| bool isTargetFuchsia() const { return TargetTriple.isOSFuchsia(); } | |
| bool isTargetWindowsMSVC() const { | |
| return TargetTriple.isWindowsMSVCEnvironment(); | |
| } | |
| bool isTargetWindowsCoreCLR() const { | |
| return TargetTriple.isWindowsCoreCLREnvironment(); | |
| } | |
| bool isTargetWindowsCygwin() const { | |
| return TargetTriple.isWindowsCygwinEnvironment(); | |
| } | |
| bool isTargetWindowsGNU() const { | |
| return TargetTriple.isWindowsGNUEnvironment(); | |
| } | |
| bool isTargetWindowsItanium() const { | |
| return TargetTriple.isWindowsItaniumEnvironment(); | |
| } | |
| bool isTargetCygMing() const { return TargetTriple.isOSCygMing(); } | |
| bool isOSWindows() const { return TargetTriple.isOSWindows(); } | |
| bool isTargetWin64() const { return Is64Bit && isOSWindows(); } | |
| bool isTargetWin32() const { return !Is64Bit && isOSWindows(); } | |
| bool isPICStyleGOT() const { return PICStyle == PICStyles::Style::GOT; } | |
| bool isPICStyleRIPRel() const { return PICStyle == PICStyles::Style::RIPRel; } | |
| bool isPICStyleStubPIC() const { | |
| return PICStyle == PICStyles::Style::StubPIC; | |
| } | |
| bool isPositionIndependent() const; | |
| bool isCallingConvWin64(CallingConv::ID CC) const { | |
| switch (CC) { | |
| // On Win64, all these conventions just use the default convention. | |
| case CallingConv::C: | |
| case CallingConv::Fast: | |
| case CallingConv::Tail: | |
| case CallingConv::Swift: | |
| case CallingConv::SwiftTail: | |
| case CallingConv::X86_FastCall: | |
| case CallingConv::X86_StdCall: | |
| case CallingConv::X86_ThisCall: | |
| case CallingConv::X86_VectorCall: | |
| case CallingConv::Intel_OCL_BI: | |
| return isTargetWin64(); | |
| // This convention allows using the Win64 convention on other targets. | |
| case CallingConv::Win64: | |
| return true; | |
| // This convention allows using the SysV convention on Windows targets. | |
| case CallingConv::X86_64_SysV: | |
| return false; | |
| // Otherwise, who knows what this is. | |
| default: | |
| return false; | |
| } | |
| } | |
| /// Classify a global variable reference for the current subtarget according | |
| /// to how we should reference it in a non-pcrel context. | |
| unsigned char classifyLocalReference(const GlobalValue *GV) const; | |
| unsigned char classifyGlobalReference(const GlobalValue *GV, | |
| const Module &M) const; | |
| unsigned char classifyGlobalReference(const GlobalValue *GV) const; | |
| /// Classify a global function reference for the current subtarget. | |
| unsigned char classifyGlobalFunctionReference(const GlobalValue *GV, | |
| const Module &M) const; | |
| unsigned char | |
| classifyGlobalFunctionReference(const GlobalValue *GV) const override; | |
| /// Classify a blockaddress reference for the current subtarget according to | |
| /// how we should reference it in a non-pcrel context. | |
| unsigned char classifyBlockAddressReference() const; | |
| /// Return true if the subtarget allows calls to immediate address. | |
| bool isLegalToCallImmediateAddr() const; | |
| /// 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; | |
| } | |
| } | |
| /// If we are using indirect thunks, we need to expand indirectbr to avoid it | |
| /// lowering to an actual indirect jump. | |
| bool enableIndirectBrExpand() const override { | |
| return useIndirectThunkBranches(); | |
| } | |
| /// Enable the MachineScheduler pass for all X86 subtargets. | |
| bool enableMachineScheduler() const override { return true; } | |
| bool enableEarlyIfConversion() const override; | |
| void getPostRAMutations(std::vector<std::unique_ptr<ScheduleDAGMutation>> | |
| &Mutations) const override; | |
| AntiDepBreakMode getAntiDepBreakMode() const override { | |
| return TargetSubtargetInfo::ANTIDEP_CRITICAL; | |
| } | |
| }; | |
| } // end namespace llvm | |
| #endif // LLVM_LIB_TARGET_X86_X86SUBTARGET_H |