//===--- TargetInfo.h - Expose information about the target -----*- 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 // //===----------------------------------------------------------------------===// /// /// \file /// Defines the clang::TargetInfo interface. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_TARGETINFO_H #define LLVM_CLANG_BASIC_TARGETINFO_H #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/BitmaskEnum.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetOptions.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Frontend/OpenMP/OMPGridValues.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" #include "llvm/TargetParser/Triple.h" #include #include #include #include namespace llvm { struct fltSemantics; } namespace clang { class DiagnosticsEngine; class LangOptions; class CodeGenOptions; class MacroBuilder; /// Contains information gathered from parsing the contents of TargetAttr. struct ParsedTargetAttr { std::vector Features; StringRef CPU; StringRef Tune; StringRef BranchProtection; StringRef Duplicate; bool operator ==(const ParsedTargetAttr &Other) const { return Duplicate == Other.Duplicate && CPU == Other.CPU && Tune == Other.Tune && BranchProtection == Other.BranchProtection && Features == Other.Features; } }; namespace Builtin { struct Info; } enum class FloatModeKind { NoFloat = 0, Half = 1 << 0, Float = 1 << 1, Double = 1 << 2, LongDouble = 1 << 3, Float128 = 1 << 4, Ibm128 = 1 << 5, LLVM_MARK_AS_BITMASK_ENUM(Ibm128) }; /// Fields controlling how types are laid out in memory; these may need to /// be copied for targets like AMDGPU that base their ABIs on an auxiliary /// CPU target. struct TransferrableTargetInfo { unsigned char PointerWidth, PointerAlign; unsigned char BoolWidth, BoolAlign; unsigned char IntWidth, IntAlign; unsigned char HalfWidth, HalfAlign; unsigned char BFloat16Width, BFloat16Align; unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align, Ibm128Align; unsigned char LargeArrayMinWidth, LargeArrayAlign; unsigned char LongWidth, LongAlign; unsigned char LongLongWidth, LongLongAlign; unsigned char Int128Align; // Fixed point bit widths unsigned char ShortAccumWidth, ShortAccumAlign; unsigned char AccumWidth, AccumAlign; unsigned char LongAccumWidth, LongAccumAlign; unsigned char ShortFractWidth, ShortFractAlign; unsigned char FractWidth, FractAlign; unsigned char LongFractWidth, LongFractAlign; // If true, unsigned fixed point types have the same number of fractional bits // as their signed counterparts, forcing the unsigned types to have one extra // bit of padding. Otherwise, unsigned fixed point types have // one more fractional bit than its corresponding signed type. This is false // by default. bool PaddingOnUnsignedFixedPoint; // Fixed point integral and fractional bit sizes // Saturated types share the same integral/fractional bits as their // corresponding unsaturated types. // For simplicity, the fractional bits in a _Fract type will be one less the // width of that _Fract type. This leaves all signed _Fract types having no // padding and unsigned _Fract types will only have 1 bit of padding after the // sign if PaddingOnUnsignedFixedPoint is set. unsigned char ShortAccumScale; unsigned char AccumScale; unsigned char LongAccumScale; unsigned char DefaultAlignForAttributeAligned; unsigned char MinGlobalAlign; unsigned short SuitableAlign; unsigned short NewAlign; unsigned MaxVectorAlign; unsigned MaxTLSAlign; const llvm::fltSemantics *HalfFormat, *BFloat16Format, *FloatFormat, *DoubleFormat, *LongDoubleFormat, *Float128Format, *Ibm128Format; ///===---- Target Data Type Query Methods -------------------------------===// enum IntType { NoInt = 0, SignedChar, UnsignedChar, SignedShort, UnsignedShort, SignedInt, UnsignedInt, SignedLong, UnsignedLong, SignedLongLong, UnsignedLongLong }; protected: IntType SizeType, IntMaxType, PtrDiffType, IntPtrType, WCharType, WIntType, Char16Type, Char32Type, Int64Type, Int16Type, SigAtomicType, ProcessIDType; /// Whether Objective-C's built-in boolean type should be signed char. /// /// Otherwise, when this flag is not set, the normal built-in boolean type is /// used. LLVM_PREFERRED_TYPE(bool) unsigned UseSignedCharForObjCBool : 1; /// Control whether the alignment of bit-field types is respected when laying /// out structures. If true, then the alignment of the bit-field type will be /// used to (a) impact the alignment of the containing structure, and (b) /// ensure that the individual bit-field will not straddle an alignment /// boundary. LLVM_PREFERRED_TYPE(bool) unsigned UseBitFieldTypeAlignment : 1; /// Whether zero length bitfields (e.g., int : 0;) force alignment of /// the next bitfield. /// /// If the alignment of the zero length bitfield is greater than the member /// that follows it, `bar', `bar' will be aligned as the type of the /// zero-length bitfield. LLVM_PREFERRED_TYPE(bool) unsigned UseZeroLengthBitfieldAlignment : 1; /// Whether zero length bitfield alignment is respected if they are the /// leading members. LLVM_PREFERRED_TYPE(bool) unsigned UseLeadingZeroLengthBitfield : 1; /// Whether explicit bit field alignment attributes are honored. LLVM_PREFERRED_TYPE(bool) unsigned UseExplicitBitFieldAlignment : 1; /// If non-zero, specifies a fixed alignment value for bitfields that follow /// zero length bitfield, regardless of the zero length bitfield type. unsigned ZeroLengthBitfieldBoundary; /// If non-zero, specifies a maximum alignment to truncate alignment /// specified in the aligned attribute of a static variable to this value. unsigned MaxAlignedAttribute; }; /// OpenCL type kinds. enum OpenCLTypeKind : uint8_t { OCLTK_Default, OCLTK_ClkEvent, OCLTK_Event, OCLTK_Image, OCLTK_Pipe, OCLTK_Queue, OCLTK_ReserveID, OCLTK_Sampler, }; /// Exposes information about the current target. /// class TargetInfo : public TransferrableTargetInfo, public RefCountedBase { std::shared_ptr TargetOpts; llvm::Triple Triple; protected: // Target values set by the ctor of the actual target implementation. Default // values are specified by the TargetInfo constructor. bool BigEndian; bool TLSSupported; bool VLASupported; bool NoAsmVariants; // True if {|} are normal characters. bool HasLegalHalfType; // True if the backend supports operations on the half // LLVM IR type. bool HalfArgsAndReturns; bool HasFloat128; bool HasFloat16; bool HasBFloat16; bool HasFullBFloat16; // True if the backend supports native bfloat16 // arithmetic. Used to determine excess precision // support in the frontend. bool HasIbm128; bool HasLongDouble; bool HasFPReturn; bool HasStrictFP; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; std::string DataLayoutString; const char *UserLabelPrefix; const char *MCountName; unsigned char RegParmMax, SSERegParmMax; TargetCXXABI TheCXXABI; const LangASMap *AddrSpaceMap; mutable StringRef PlatformName; mutable VersionTuple PlatformMinVersion; LLVM_PREFERRED_TYPE(bool) unsigned HasAlignMac68kSupport : 1; LLVM_PREFERRED_TYPE(FloatModeKind) unsigned RealTypeUsesObjCFPRetMask : llvm::BitWidth; LLVM_PREFERRED_TYPE(bool) unsigned ComplexLongDoubleUsesFP2Ret : 1; LLVM_PREFERRED_TYPE(bool) unsigned HasBuiltinMSVaList : 1; LLVM_PREFERRED_TYPE(bool) unsigned IsRenderScriptTarget : 1; LLVM_PREFERRED_TYPE(bool) unsigned HasAArch64SVETypes : 1; LLVM_PREFERRED_TYPE(bool) unsigned HasRISCVVTypes : 1; LLVM_PREFERRED_TYPE(bool) unsigned AllowAMDGPUUnsafeFPAtomics : 1; unsigned ARMCDECoprocMask : 8; unsigned MaxOpenCLWorkGroupSize; std::optional MaxBitIntWidth; std::optional DarwinTargetVariantTriple; // TargetInfo Constructor. Default initializes all fields. TargetInfo(const llvm::Triple &T); // UserLabelPrefix must match DL's getGlobalPrefix() when interpreted // as a DataLayout object. void resetDataLayout(StringRef DL, const char *UserLabelPrefix = ""); // Target features that are read-only and should not be disabled/enabled // by command line options. Such features are for emitting predefined // macros or checking availability of builtin functions and can be omitted // in function attributes in IR. llvm::StringSet<> ReadOnlyFeatures; public: /// Construct a target for the given options. /// /// \param Opts - The options to use to initialize the target. The target may /// modify the options to canonicalize the target feature information to match /// what the backend expects. static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr &Opts); virtual ~TargetInfo(); /// Retrieve the target options. TargetOptions &getTargetOpts() const { assert(TargetOpts && "Missing target options"); return *TargetOpts; } /// The different kinds of __builtin_va_list types defined by /// the target implementation. enum BuiltinVaListKind { /// typedef char* __builtin_va_list; CharPtrBuiltinVaList = 0, /// typedef void* __builtin_va_list; VoidPtrBuiltinVaList, /// __builtin_va_list as defined by the AArch64 ABI /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf AArch64ABIBuiltinVaList, /// __builtin_va_list as defined by the PNaCl ABI: /// http://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Machine-Types PNaClABIBuiltinVaList, /// __builtin_va_list as defined by the Power ABI: /// https://www.power.org /// /resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Embedded.pdf PowerABIBuiltinVaList, /// __builtin_va_list as defined by the x86-64 ABI: /// http://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf X86_64ABIBuiltinVaList, /// __builtin_va_list as defined by ARM AAPCS ABI /// http://infocenter.arm.com // /help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf AAPCSABIBuiltinVaList, // typedef struct __va_list_tag // { // long __gpr; // long __fpr; // void *__overflow_arg_area; // void *__reg_save_area; // } va_list[1]; SystemZBuiltinVaList, // typedef struct __va_list_tag { // void *__current_saved_reg_area_pointer; // void *__saved_reg_area_end_pointer; // void *__overflow_area_pointer; //} va_list; HexagonBuiltinVaList }; protected: /// Specify if mangling based on address space map should be used or /// not for language specific address spaces bool UseAddrSpaceMapMangling; public: IntType getSizeType() const { return SizeType; } IntType getSignedSizeType() const { switch (SizeType) { case UnsignedShort: return SignedShort; case UnsignedInt: return SignedInt; case UnsignedLong: return SignedLong; case UnsignedLongLong: return SignedLongLong; default: llvm_unreachable("Invalid SizeType"); } } IntType getIntMaxType() const { return IntMaxType; } IntType getUIntMaxType() const { return getCorrespondingUnsignedType(IntMaxType); } IntType getPtrDiffType(LangAS AddrSpace) const { return AddrSpace == LangAS::Default ? PtrDiffType : getPtrDiffTypeV(AddrSpace); } IntType getUnsignedPtrDiffType(LangAS AddrSpace) const { return getCorrespondingUnsignedType(getPtrDiffType(AddrSpace)); } IntType getIntPtrType() const { return IntPtrType; } IntType getUIntPtrType() const { return getCorrespondingUnsignedType(IntPtrType); } IntType getWCharType() const { return WCharType; } IntType getWIntType() const { return WIntType; } IntType getChar16Type() const { return Char16Type; } IntType getChar32Type() const { return Char32Type; } IntType getInt64Type() const { return Int64Type; } IntType getUInt64Type() const { return getCorrespondingUnsignedType(Int64Type); } IntType getInt16Type() const { return Int16Type; } IntType getUInt16Type() const { return getCorrespondingUnsignedType(Int16Type); } IntType getSigAtomicType() const { return SigAtomicType; } IntType getProcessIDType() const { return ProcessIDType; } static IntType getCorrespondingUnsignedType(IntType T) { switch (T) { case SignedChar: return UnsignedChar; case SignedShort: return UnsignedShort; case SignedInt: return UnsignedInt; case SignedLong: return UnsignedLong; case SignedLongLong: return UnsignedLongLong; default: llvm_unreachable("Unexpected signed integer type"); } } /// In the event this target uses the same number of fractional bits for its /// unsigned types as it does with its signed counterparts, there will be /// exactly one bit of padding. /// Return true if unsigned fixed point types have padding for this target. bool doUnsignedFixedPointTypesHavePadding() const { return PaddingOnUnsignedFixedPoint; } /// Return the width (in bits) of the specified integer type enum. /// /// For example, SignedInt -> getIntWidth(). unsigned getTypeWidth(IntType T) const; /// Return integer type with specified width. virtual IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const; /// Return the smallest integer type with at least the specified width. virtual IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const; /// Return floating point type with specified width. On PPC, there are /// three possible types for 128-bit floating point: "PPC double-double", /// IEEE 754R quad precision, and "long double" (which under the covers /// is represented as one of those two). At this time, there is no support /// for an explicit "PPC double-double" type (i.e. __ibm128) so we only /// need to differentiate between "long double" and IEEE quad precision. FloatModeKind getRealTypeByWidth(unsigned BitWidth, FloatModeKind ExplicitType) const; /// Return the alignment (in bits) of the specified integer type enum. /// /// For example, SignedInt -> getIntAlign(). unsigned getTypeAlign(IntType T) const; /// Returns true if the type is signed; false otherwise. static bool isTypeSigned(IntType T); /// Return the width of pointers on this target, for the /// specified address space. uint64_t getPointerWidth(LangAS AddrSpace) const { return AddrSpace == LangAS::Default ? PointerWidth : getPointerWidthV(AddrSpace); } uint64_t getPointerAlign(LangAS AddrSpace) const { return AddrSpace == LangAS::Default ? PointerAlign : getPointerAlignV(AddrSpace); } /// Return the maximum width of pointers on this target. virtual uint64_t getMaxPointerWidth() const { return PointerWidth; } /// Get integer value for null pointer. /// \param AddrSpace address space of pointee in source language. virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; } /// Return the size of '_Bool' and C++ 'bool' for this target, in bits. unsigned getBoolWidth() const { return BoolWidth; } /// Return the alignment of '_Bool' and C++ 'bool' for this target. unsigned getBoolAlign() const { return BoolAlign; } unsigned getCharWidth() const { return 8; } // FIXME unsigned getCharAlign() const { return 8; } // FIXME /// Return the size of 'signed short' and 'unsigned short' for this /// target, in bits. unsigned getShortWidth() const { return 16; } // FIXME /// Return the alignment of 'signed short' and 'unsigned short' for /// this target. unsigned getShortAlign() const { return 16; } // FIXME /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for /// this target, in bits. unsigned getIntWidth() const { return IntWidth; } unsigned getIntAlign() const { return IntAlign; } /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' /// for this target, in bits. unsigned getLongWidth() const { return LongWidth; } unsigned getLongAlign() const { return LongAlign; } /// getLongLongWidth/Align - Return the size of 'signed long long' and /// 'unsigned long long' for this target, in bits. unsigned getLongLongWidth() const { return LongLongWidth; } unsigned getLongLongAlign() const { return LongLongAlign; } /// getInt128Align() - Returns the alignment of Int128. unsigned getInt128Align() const { return Int128Align; } /// getShortAccumWidth/Align - Return the size of 'signed short _Accum' and /// 'unsigned short _Accum' for this target, in bits. unsigned getShortAccumWidth() const { return ShortAccumWidth; } unsigned getShortAccumAlign() const { return ShortAccumAlign; } /// getAccumWidth/Align - Return the size of 'signed _Accum' and /// 'unsigned _Accum' for this target, in bits. unsigned getAccumWidth() const { return AccumWidth; } unsigned getAccumAlign() const { return AccumAlign; } /// getLongAccumWidth/Align - Return the size of 'signed long _Accum' and /// 'unsigned long _Accum' for this target, in bits. unsigned getLongAccumWidth() const { return LongAccumWidth; } unsigned getLongAccumAlign() const { return LongAccumAlign; } /// getShortFractWidth/Align - Return the size of 'signed short _Fract' and /// 'unsigned short _Fract' for this target, in bits. unsigned getShortFractWidth() const { return ShortFractWidth; } unsigned getShortFractAlign() const { return ShortFractAlign; } /// getFractWidth/Align - Return the size of 'signed _Fract' and /// 'unsigned _Fract' for this target, in bits. unsigned getFractWidth() const { return FractWidth; } unsigned getFractAlign() const { return FractAlign; } /// getLongFractWidth/Align - Return the size of 'signed long _Fract' and /// 'unsigned long _Fract' for this target, in bits. unsigned getLongFractWidth() const { return LongFractWidth; } unsigned getLongFractAlign() const { return LongFractAlign; } /// getShortAccumScale/IBits - Return the number of fractional/integral bits /// in a 'signed short _Accum' type. unsigned getShortAccumScale() const { return ShortAccumScale; } unsigned getShortAccumIBits() const { return ShortAccumWidth - ShortAccumScale - 1; } /// getAccumScale/IBits - Return the number of fractional/integral bits /// in a 'signed _Accum' type. unsigned getAccumScale() const { return AccumScale; } unsigned getAccumIBits() const { return AccumWidth - AccumScale - 1; } /// getLongAccumScale/IBits - Return the number of fractional/integral bits /// in a 'signed long _Accum' type. unsigned getLongAccumScale() const { return LongAccumScale; } unsigned getLongAccumIBits() const { return LongAccumWidth - LongAccumScale - 1; } /// getUnsignedShortAccumScale/IBits - Return the number of /// fractional/integral bits in a 'unsigned short _Accum' type. unsigned getUnsignedShortAccumScale() const { return PaddingOnUnsignedFixedPoint ? ShortAccumScale : ShortAccumScale + 1; } unsigned getUnsignedShortAccumIBits() const { return PaddingOnUnsignedFixedPoint ? getShortAccumIBits() : ShortAccumWidth - getUnsignedShortAccumScale(); } /// getUnsignedAccumScale/IBits - Return the number of fractional/integral /// bits in a 'unsigned _Accum' type. unsigned getUnsignedAccumScale() const { return PaddingOnUnsignedFixedPoint ? AccumScale : AccumScale + 1; } unsigned getUnsignedAccumIBits() const { return PaddingOnUnsignedFixedPoint ? getAccumIBits() : AccumWidth - getUnsignedAccumScale(); } /// getUnsignedLongAccumScale/IBits - Return the number of fractional/integral /// bits in a 'unsigned long _Accum' type. unsigned getUnsignedLongAccumScale() const { return PaddingOnUnsignedFixedPoint ? LongAccumScale : LongAccumScale + 1; } unsigned getUnsignedLongAccumIBits() const { return PaddingOnUnsignedFixedPoint ? getLongAccumIBits() : LongAccumWidth - getUnsignedLongAccumScale(); } /// getShortFractScale - Return the number of fractional bits /// in a 'signed short _Fract' type. unsigned getShortFractScale() const { return ShortFractWidth - 1; } /// getFractScale - Return the number of fractional bits /// in a 'signed _Fract' type. unsigned getFractScale() const { return FractWidth - 1; } /// getLongFractScale - Return the number of fractional bits /// in a 'signed long _Fract' type. unsigned getLongFractScale() const { return LongFractWidth - 1; } /// getUnsignedShortFractScale - Return the number of fractional bits /// in a 'unsigned short _Fract' type. unsigned getUnsignedShortFractScale() const { return PaddingOnUnsignedFixedPoint ? getShortFractScale() : getShortFractScale() + 1; } /// getUnsignedFractScale - Return the number of fractional bits /// in a 'unsigned _Fract' type. unsigned getUnsignedFractScale() const { return PaddingOnUnsignedFixedPoint ? getFractScale() : getFractScale() + 1; } /// getUnsignedLongFractScale - Return the number of fractional bits /// in a 'unsigned long _Fract' type. unsigned getUnsignedLongFractScale() const { return PaddingOnUnsignedFixedPoint ? getLongFractScale() : getLongFractScale() + 1; } /// Determine whether the __int128 type is supported on this target. virtual bool hasInt128Type() const { return (getPointerWidth(LangAS::Default) >= 64) || getTargetOpts().ForceEnableInt128; } // FIXME /// Determine whether the _BitInt type is supported on this target. This /// limitation is put into place for ABI reasons. /// FIXME: _BitInt is a required type in C23, so there's not much utility in /// asking whether the target supported it or not; I think this should be /// removed once backends have been alerted to the type and have had the /// chance to do implementation work if needed. virtual bool hasBitIntType() const { return false; } // Different targets may support a different maximum width for the _BitInt // type, depending on what operations are supported. virtual size_t getMaxBitIntWidth() const { // Consider -fexperimental-max-bitint-width= first. if (MaxBitIntWidth) return std::min(*MaxBitIntWidth, llvm::IntegerType::MAX_INT_BITS); // FIXME: this value should be llvm::IntegerType::MAX_INT_BITS, which is // maximum bit width that LLVM claims its IR can support. However, most // backends currently have a bug where they only support float to int // conversion (and vice versa) on types that are <= 128 bits and crash // otherwise. We're setting the max supported value to 128 to be // conservative. return 128; } /// Determine whether _Float16 is supported on this target. virtual bool hasLegalHalfType() const { return HasLegalHalfType; } /// Whether half args and returns are supported. virtual bool allowHalfArgsAndReturns() const { return HalfArgsAndReturns; } /// Determine whether the __float128 type is supported on this target. virtual bool hasFloat128Type() const { return HasFloat128; } /// Determine whether the _Float16 type is supported on this target. virtual bool hasFloat16Type() const { return HasFloat16; } /// Determine whether the _BFloat16 type is supported on this target. virtual bool hasBFloat16Type() const { return HasBFloat16 || HasFullBFloat16; } /// Determine whether the BFloat type is fully supported on this target, i.e /// arithemtic operations. virtual bool hasFullBFloat16Type() const { return HasFullBFloat16; } /// Determine whether the __ibm128 type is supported on this target. virtual bool hasIbm128Type() const { return HasIbm128; } /// Determine whether the long double type is supported on this target. virtual bool hasLongDoubleType() const { return HasLongDouble; } /// Determine whether return of a floating point value is supported /// on this target. virtual bool hasFPReturn() const { return HasFPReturn; } /// Determine whether constrained floating point is supported on this target. virtual bool hasStrictFP() const { return HasStrictFP; } /// Return the alignment that is the largest alignment ever used for any /// scalar/SIMD data type on the target machine you are compiling for /// (including types with an extended alignment requirement). unsigned getSuitableAlign() const { return SuitableAlign; } /// Return the default alignment for __attribute__((aligned)) on /// this target, to be used if no alignment value is specified. unsigned getDefaultAlignForAttributeAligned() const { return DefaultAlignForAttributeAligned; } /// getMinGlobalAlign - Return the minimum alignment of a global variable, /// unless its alignment is explicitly reduced via attributes. virtual unsigned getMinGlobalAlign (uint64_t) const { return MinGlobalAlign; } /// Return the largest alignment for which a suitably-sized allocation with /// '::operator new(size_t)' is guaranteed to produce a correctly-aligned /// pointer. unsigned getNewAlign() const { return NewAlign ? NewAlign : std::max(LongDoubleAlign, LongLongAlign); } /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in /// bits. unsigned getWCharWidth() const { return getTypeWidth(WCharType); } unsigned getWCharAlign() const { return getTypeAlign(WCharType); } /// getChar16Width/Align - Return the size of 'char16_t' for this target, in /// bits. unsigned getChar16Width() const { return getTypeWidth(Char16Type); } unsigned getChar16Align() const { return getTypeAlign(Char16Type); } /// getChar32Width/Align - Return the size of 'char32_t' for this target, in /// bits. unsigned getChar32Width() const { return getTypeWidth(Char32Type); } unsigned getChar32Align() const { return getTypeAlign(Char32Type); } /// getHalfWidth/Align/Format - Return the size/align/format of 'half'. unsigned getHalfWidth() const { return HalfWidth; } unsigned getHalfAlign() const { return HalfAlign; } const llvm::fltSemantics &getHalfFormat() const { return *HalfFormat; } /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. unsigned getFloatWidth() const { return FloatWidth; } unsigned getFloatAlign() const { return FloatAlign; } const llvm::fltSemantics &getFloatFormat() const { return *FloatFormat; } /// getBFloat16Width/Align/Format - Return the size/align/format of '__bf16'. unsigned getBFloat16Width() const { return BFloat16Width; } unsigned getBFloat16Align() const { return BFloat16Align; } const llvm::fltSemantics &getBFloat16Format() const { return *BFloat16Format; } /// getDoubleWidth/Align/Format - Return the size/align/format of 'double'. unsigned getDoubleWidth() const { return DoubleWidth; } unsigned getDoubleAlign() const { return DoubleAlign; } const llvm::fltSemantics &getDoubleFormat() const { return *DoubleFormat; } /// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long /// double'. unsigned getLongDoubleWidth() const { return LongDoubleWidth; } unsigned getLongDoubleAlign() const { return LongDoubleAlign; } const llvm::fltSemantics &getLongDoubleFormat() const { return *LongDoubleFormat; } /// getFloat128Width/Align/Format - Return the size/align/format of /// '__float128'. unsigned getFloat128Width() const { return 128; } unsigned getFloat128Align() const { return Float128Align; } const llvm::fltSemantics &getFloat128Format() const { return *Float128Format; } /// getIbm128Width/Align/Format - Return the size/align/format of /// '__ibm128'. unsigned getIbm128Width() const { return 128; } unsigned getIbm128Align() const { return Ibm128Align; } const llvm::fltSemantics &getIbm128Format() const { return *Ibm128Format; } /// Return the mangled code of long double. virtual const char *getLongDoubleMangling() const { return "e"; } /// Return the mangled code of __float128. virtual const char *getFloat128Mangling() const { return "g"; } /// Return the mangled code of __ibm128. virtual const char *getIbm128Mangling() const { llvm_unreachable("ibm128 not implemented on this target"); } /// Return the mangled code of bfloat. virtual const char *getBFloat16Mangling() const { return "DF16b"; } /// Return the value for the C99 FLT_EVAL_METHOD macro. virtual LangOptions::FPEvalMethodKind getFPEvalMethod() const { return LangOptions::FPEvalMethodKind::FEM_Source; } virtual bool supportSourceEvalMethod() const { return true; } // getLargeArrayMinWidth/Align - Return the minimum array size that is // 'large' and its alignment. unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; } unsigned getLargeArrayAlign() const { return LargeArrayAlign; } /// Return the maximum width lock-free atomic operation which will /// ever be supported for the given target unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; } /// Return the maximum width lock-free atomic operation which can be /// inlined given the supported features of the given target. unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } /// Set the maximum inline or promote width lock-free atomic operation /// for the given target. virtual void setMaxAtomicWidth() {} /// Returns true if the given target supports lock-free atomic /// operations at the specified width and alignment. virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, uint64_t AlignmentInBits) const { return AtomicSizeInBits <= AlignmentInBits && AtomicSizeInBits <= getMaxAtomicInlineWidth() && (AtomicSizeInBits <= getCharWidth() || llvm::isPowerOf2_64(AtomicSizeInBits / getCharWidth())); } /// Return the maximum vector alignment supported for the given target. unsigned getMaxVectorAlign() const { return MaxVectorAlign; } unsigned getMaxOpenCLWorkGroupSize() const { return MaxOpenCLWorkGroupSize; } /// Return the alignment (in bits) of the thrown exception object. This is /// only meaningful for targets that allocate C++ exceptions in a system /// runtime, such as those using the Itanium C++ ABI. virtual unsigned getExnObjectAlignment() const { // Itanium says that an _Unwind_Exception has to be "double-word" // aligned (and thus the end of it is also so-aligned), meaning 16 // bytes. Of course, that was written for the actual Itanium, // which is a 64-bit platform. Classically, the ABI doesn't really // specify the alignment on other platforms, but in practice // libUnwind declares the struct with __attribute__((aligned)), so // we assume that alignment here. (It's generally 16 bytes, but // some targets overwrite it.) return getDefaultAlignForAttributeAligned(); } /// Return the size of intmax_t and uintmax_t for this target, in bits. unsigned getIntMaxTWidth() const { return getTypeWidth(IntMaxType); } // Return the size of unwind_word for this target. virtual unsigned getUnwindWordWidth() const { return getPointerWidth(LangAS::Default); } /// Return the "preferred" register width on this target. virtual unsigned getRegisterWidth() const { // Currently we assume the register width on the target matches the pointer // width, we can introduce a new variable for this if/when some target wants // it. return PointerWidth; } /// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro, /// which is the prefix given to user symbols by default. /// /// On most platforms this is "", but it is "_" on some. const char *getUserLabelPrefix() const { return UserLabelPrefix; } /// Returns the name of the mcount instrumentation function. const char *getMCountName() const { return MCountName; } /// Check if the Objective-C built-in boolean type should be signed /// char. /// /// Otherwise, if this returns false, the normal built-in boolean type /// should also be used for Objective-C. bool useSignedCharForObjCBool() const { return UseSignedCharForObjCBool; } void noSignedCharForObjCBool() { UseSignedCharForObjCBool = false; } /// Check whether the alignment of bit-field types is respected /// when laying out structures. bool useBitFieldTypeAlignment() const { return UseBitFieldTypeAlignment; } /// Check whether zero length bitfields should force alignment of /// the next member. bool useZeroLengthBitfieldAlignment() const { return UseZeroLengthBitfieldAlignment; } /// Check whether zero length bitfield alignment is respected if they are /// leading members. bool useLeadingZeroLengthBitfield() const { return UseLeadingZeroLengthBitfield; } /// Get the fixed alignment value in bits for a member that follows /// a zero length bitfield. unsigned getZeroLengthBitfieldBoundary() const { return ZeroLengthBitfieldBoundary; } /// Get the maximum alignment in bits for a static variable with /// aligned attribute. unsigned getMaxAlignedAttribute() const { return MaxAlignedAttribute; } /// Check whether explicit bitfield alignment attributes should be // honored, as in "__attribute__((aligned(2))) int b : 1;". bool useExplicitBitFieldAlignment() const { return UseExplicitBitFieldAlignment; } /// Check whether this target support '\#pragma options align=mac68k'. bool hasAlignMac68kSupport() const { return HasAlignMac68kSupport; } /// Return the user string for the specified integer type enum. /// /// For example, SignedShort -> "short". static const char *getTypeName(IntType T); /// Return the constant suffix for the specified integer type enum. /// /// For example, SignedLong -> "L". const char *getTypeConstantSuffix(IntType T) const; /// Return the printf format modifier for the specified /// integer type enum. /// /// For example, SignedLong -> "l". static const char *getTypeFormatModifier(IntType T); /// Check whether the given real type should use the "fpret" flavor of /// Objective-C message passing on this target. bool useObjCFPRetForRealType(FloatModeKind T) const { return (int)((FloatModeKind)RealTypeUsesObjCFPRetMask & T); } /// Check whether _Complex long double should use the "fp2ret" flavor /// of Objective-C message passing on this target. bool useObjCFP2RetForComplexLongDouble() const { return ComplexLongDoubleUsesFP2Ret; } /// Check whether llvm intrinsics such as llvm.convert.to.fp16 should be used /// to convert to and from __fp16. /// FIXME: This function should be removed once all targets stop using the /// conversion intrinsics. virtual bool useFP16ConversionIntrinsics() const { return true; } /// Specify if mangling based on address space map should be used or /// not for language specific address spaces bool useAddressSpaceMapMangling() const { return UseAddrSpaceMapMangling; } ///===---- Other target property query methods --------------------------===// /// Appends the target-specific \#define values for this /// target set to the specified buffer. virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const = 0; /// Return information about target-specific builtins for /// the current primary target, and info about which builtins are non-portable /// across the current set of primary and secondary targets. virtual ArrayRef getTargetBuiltins() const = 0; /// Returns target-specific min and max values VScale_Range. virtual std::optional> getVScaleRange(const LangOptions &LangOpts) const { return std::nullopt; } /// The __builtin_clz* and __builtin_ctz* built-in /// functions are specified to have undefined results for zero inputs, but /// on targets that support these operations in a way that provides /// well-defined results for zero without loss of performance, it is a good /// idea to avoid optimizing based on that undef behavior. virtual bool isCLZForZeroUndef() const { return true; } /// Returns the kind of __builtin_va_list type that should be used /// with this target. virtual BuiltinVaListKind getBuiltinVaListKind() const = 0; /// Returns whether or not type \c __builtin_ms_va_list type is /// available on this target. bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; } /// Returns true for RenderScript. bool isRenderScriptTarget() const { return IsRenderScriptTarget; } /// Returns whether or not the AArch64 SVE built-in types are /// available on this target. bool hasAArch64SVETypes() const { return HasAArch64SVETypes; } /// Returns whether or not the RISC-V V built-in types are /// available on this target. bool hasRISCVVTypes() const { return HasRISCVVTypes; } /// Returns whether or not the AMDGPU unsafe floating point atomics are /// allowed. bool allowAMDGPUUnsafeFPAtomics() const { return AllowAMDGPUUnsafeFPAtomics; } /// For ARM targets returns a mask defining which coprocessors are configured /// as Custom Datapath. uint32_t getARMCDECoprocMask() const { return ARMCDECoprocMask; } /// Returns whether the passed in string is a valid clobber in an /// inline asm statement. /// /// This is used by Sema. bool isValidClobber(StringRef Name) const; /// Returns whether the passed in string is a valid register name /// according to GCC. /// /// This is used by Sema for inline asm statements. virtual bool isValidGCCRegisterName(StringRef Name) const; /// Returns the "normalized" GCC register name. /// /// ReturnCannonical true will return the register name without any additions /// such as "{}" or "%" in it's canonical form, for example: /// ReturnCanonical = true and Name = "rax", will return "ax". StringRef getNormalizedGCCRegisterName(StringRef Name, bool ReturnCanonical = false) const; virtual bool isSPRegName(StringRef) const { return false; } /// Extracts a register from the passed constraint (if it is a /// single-register constraint) and the asm label expression related to a /// variable in the input or output list of an inline asm statement. /// /// This function is used by Sema in order to diagnose conflicts between /// the clobber list and the input/output lists. virtual StringRef getConstraintRegister(StringRef Constraint, StringRef Expression) const { return ""; } struct ConstraintInfo { enum { CI_None = 0x00, CI_AllowsMemory = 0x01, CI_AllowsRegister = 0x02, CI_ReadWrite = 0x04, // "+r" output constraint (read and write). CI_HasMatchingInput = 0x08, // This output operand has a matching input. CI_ImmediateConstant = 0x10, // This operand must be an immediate constant CI_EarlyClobber = 0x20, // "&" output constraint (early clobber). }; unsigned Flags; int TiedOperand; struct { int Min; int Max; bool isConstrained; } ImmRange; llvm::SmallSet ImmSet; std::string ConstraintStr; // constraint: "=rm" std::string Name; // Operand name: [foo] with no []'s. public: ConstraintInfo(StringRef ConstraintStr, StringRef Name) : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), Name(Name.str()) { ImmRange.Min = ImmRange.Max = 0; ImmRange.isConstrained = false; } const std::string &getConstraintStr() const { return ConstraintStr; } const std::string &getName() const { return Name; } bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } bool earlyClobber() { return (Flags & CI_EarlyClobber) != 0; } bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } /// Return true if this output operand has a matching /// (tied) input operand. bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; } /// Return true if this input operand is a matching /// constraint that ties it to an output operand. /// /// If this returns true then getTiedOperand will indicate which output /// operand this is tied to. bool hasTiedOperand() const { return TiedOperand != -1; } unsigned getTiedOperand() const { assert(hasTiedOperand() && "Has no tied operand!"); return (unsigned)TiedOperand; } bool requiresImmediateConstant() const { return (Flags & CI_ImmediateConstant) != 0; } bool isValidAsmImmediate(const llvm::APInt &Value) const { if (!ImmSet.empty()) return Value.isSignedIntN(32) && ImmSet.contains(Value.getZExtValue()); return !ImmRange.isConstrained || (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max)); } void setIsReadWrite() { Flags |= CI_ReadWrite; } void setEarlyClobber() { Flags |= CI_EarlyClobber; } void setAllowsMemory() { Flags |= CI_AllowsMemory; } void setAllowsRegister() { Flags |= CI_AllowsRegister; } void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } void setRequiresImmediate(int Min, int Max) { Flags |= CI_ImmediateConstant; ImmRange.Min = Min; ImmRange.Max = Max; ImmRange.isConstrained = true; } void setRequiresImmediate(llvm::ArrayRef Exacts) { Flags |= CI_ImmediateConstant; for (int Exact : Exacts) ImmSet.insert(Exact); } void setRequiresImmediate(int Exact) { Flags |= CI_ImmediateConstant; ImmSet.insert(Exact); } void setRequiresImmediate() { Flags |= CI_ImmediateConstant; } /// Indicate that this is an input operand that is tied to /// the specified output operand. /// /// Copy over the various constraint information from the output. void setTiedOperand(unsigned N, ConstraintInfo &Output) { Output.setHasMatchingInput(); Flags = Output.Flags; TiedOperand = N; // Don't copy Name or constraint string. } }; /// Validate register name used for global register variables. /// /// This function returns true if the register passed in RegName can be used /// for global register variables on this target. In addition, it returns /// true in HasSizeMismatch if the size of the register doesn't match the /// variable size passed in RegSize. virtual bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const { HasSizeMismatch = false; return true; } // validateOutputConstraint, validateInputConstraint - Checks that // a constraint is valid and provides information about it. // FIXME: These should return a real error instead of just true/false. bool validateOutputConstraint(ConstraintInfo &Info) const; bool validateInputConstraint(MutableArrayRef OutputConstraints, ConstraintInfo &info) const; virtual bool validateOutputSize(const llvm::StringMap &FeatureMap, StringRef /*Constraint*/, unsigned /*Size*/) const { return true; } virtual bool validateInputSize(const llvm::StringMap &FeatureMap, StringRef /*Constraint*/, unsigned /*Size*/) const { return true; } virtual bool validateConstraintModifier(StringRef /*Constraint*/, char /*Modifier*/, unsigned /*Size*/, std::string &/*SuggestedModifier*/) const { return true; } virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const = 0; bool resolveSymbolicName(const char *&Name, ArrayRef OutputConstraints, unsigned &Index) const; // Constraint parm will be left pointing at the last character of // the constraint. In practice, it won't be changed unless the // constraint is longer than one character. virtual std::string convertConstraint(const char *&Constraint) const { // 'p' defaults to 'r', but can be overridden by targets. if (*Constraint == 'p') return std::string("r"); return std::string(1, *Constraint); } /// Replace some escaped characters with another string based on /// target-specific rules virtual std::optional handleAsmEscapedChar(char C) const { return std::nullopt; } /// Returns a string of target-specific clobbers, in LLVM format. virtual std::string_view getClobbers() const = 0; /// Returns true if NaN encoding is IEEE 754-2008. /// Only MIPS allows a different encoding. virtual bool isNan2008() const { return true; } /// Returns the target triple of the primary target. const llvm::Triple &getTriple() const { return Triple; } /// Returns the target ID if supported. virtual std::optional getTargetID() const { return std::nullopt; } const char *getDataLayoutString() const { assert(!DataLayoutString.empty() && "Uninitialized DataLayout!"); return DataLayoutString.c_str(); } struct GCCRegAlias { const char * const Aliases[5]; const char * const Register; }; struct AddlRegName { const char * const Names[5]; const unsigned RegNum; }; /// Does this target support "protected" visibility? /// /// Any target which dynamic libraries will naturally support /// something like "default" (meaning that the symbol is visible /// outside this shared object) and "hidden" (meaning that it isn't) /// visibilities, but "protected" is really an ELF-specific concept /// with weird semantics designed around the convenience of dynamic /// linker implementations. Which is not to suggest that there's /// consistent target-independent semantics for "default" visibility /// either; the entire thing is pretty badly mangled. virtual bool hasProtectedVisibility() const { return true; } /// Does this target aim for semantic compatibility with /// Microsoft C++ code using dllimport/export attributes? virtual bool shouldDLLImportComdatSymbols() const { return getTriple().isWindowsMSVCEnvironment() || getTriple().isWindowsItaniumEnvironment() || getTriple().isPS(); } // Does this target have PS4 specific dllimport/export handling? virtual bool hasPS4DLLImportExport() const { return getTriple().isPS() || // Windows Itanium support allows for testing the SCEI flavour of // dllimport/export handling on a Windows system. (getTriple().isWindowsItaniumEnvironment() && getTriple().getVendor() == llvm::Triple::SCEI); } /// Set forced language options. /// /// Apply changes to the target information with respect to certain /// language options which change the target configuration and adjust /// the language based on the target options where applicable. virtual void adjust(DiagnosticsEngine &Diags, LangOptions &Opts); /// Initialize the map with the default set of target features for the /// CPU this should include all legal feature strings on the target. /// /// \return False on error (invalid features). virtual bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeatureVec) const; /// Get the ABI currently in use. virtual StringRef getABI() const { return StringRef(); } /// Get the C++ ABI currently in use. TargetCXXABI getCXXABI() const { return TheCXXABI; } /// Target the specified CPU. /// /// \return False on error (invalid CPU name). virtual bool setCPU(const std::string &Name) { return false; } /// Fill a SmallVectorImpl with the valid values to setCPU. virtual void fillValidCPUList(SmallVectorImpl &Values) const {} /// Fill a SmallVectorImpl with the valid values for tuning CPU. virtual void fillValidTuneCPUList(SmallVectorImpl &Values) const { fillValidCPUList(Values); } /// Determine whether this TargetInfo supports the given CPU name. virtual bool isValidCPUName(StringRef Name) const { return true; } /// Determine whether this TargetInfo supports the given CPU name for /// tuning. virtual bool isValidTuneCPUName(StringRef Name) const { return isValidCPUName(Name); } virtual ParsedTargetAttr parseTargetAttr(StringRef Str) const; /// Determine whether this TargetInfo supports tune in target attribute. virtual bool supportsTargetAttributeTune() const { return false; } /// Use the specified ABI. /// /// \return False on error (invalid ABI name). virtual bool setABI(const std::string &Name) { return false; } /// Use the specified unit for FP math. /// /// \return False on error (invalid unit name). virtual bool setFPMath(StringRef Name) { return false; } /// Check if target has a given feature enabled virtual bool hasFeatureEnabled(const llvm::StringMap &Features, StringRef Name) const { return Features.lookup(Name); } /// Enable or disable a specific target feature; /// the feature name must be valid. virtual void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const { Features[Name] = Enabled; } /// Determine whether this TargetInfo supports the given feature. virtual bool isValidFeatureName(StringRef Feature) const { return true; } /// Returns true if feature has an impact on target code /// generation. virtual bool doesFeatureAffectCodeGen(StringRef Feature) const { return true; } /// For given feature return dependent ones. virtual StringRef getFeatureDependencies(StringRef Feature) const { return StringRef(); } struct BranchProtectionInfo { LangOptions::SignReturnAddressScopeKind SignReturnAddr = LangOptions::SignReturnAddressScopeKind::None; LangOptions::SignReturnAddressKeyKind SignKey = LangOptions::SignReturnAddressKeyKind::AKey; bool BranchTargetEnforcement = false; bool BranchProtectionPAuthLR = false; bool GuardedControlStack = false; }; /// Determine if the Architecture in this TargetInfo supports branch /// protection virtual bool isBranchProtectionSupportedArch(StringRef Arch) const { return false; } /// Determine if this TargetInfo supports the given branch protection /// specification virtual bool validateBranchProtection(StringRef Spec, StringRef Arch, BranchProtectionInfo &BPI, StringRef &Err) const { Err = ""; return false; } /// Perform initialization based on the user configured /// set of features (e.g., +sse4). /// /// The list is guaranteed to have at most one entry per feature. /// /// The target may modify the features list, to change which options are /// passed onwards to the backend. /// FIXME: This part should be fixed so that we can change handleTargetFeatures /// to merely a TargetInfo initialization routine. /// /// \return False on error. virtual bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { return true; } /// Determine whether the given target has the given feature. virtual bool hasFeature(StringRef Feature) const { return false; } /// Determine whether the given target feature is read only. bool isReadOnlyFeature(StringRef Feature) const { return ReadOnlyFeatures.count(Feature); } /// Identify whether this target supports multiversioning of functions, /// which requires support for cpu_supports and cpu_is functionality. bool supportsMultiVersioning() const { return getTriple().isX86() || getTriple().isAArch64(); } /// Identify whether this target supports IFuncs. bool supportsIFunc() const { if (getTriple().isOSBinFormatMachO()) return true; return getTriple().isOSBinFormatELF() && ((getTriple().isOSLinux() && !getTriple().isMusl()) || getTriple().isOSFreeBSD()); } // Validate the contents of the __builtin_cpu_supports(const char*) // argument. virtual bool validateCpuSupports(StringRef Name) const { return false; } // Return the target-specific priority for features/cpus/vendors so // that they can be properly sorted for checking. virtual unsigned multiVersionSortPriority(StringRef Name) const { return 0; } // Return the target-specific cost for feature // that taken into account in priority sorting. virtual unsigned multiVersionFeatureCost() const { return 0; } // Validate the contents of the __builtin_cpu_is(const char*) // argument. virtual bool validateCpuIs(StringRef Name) const { return false; } // Validate a cpu_dispatch/cpu_specific CPU option, which is a different list // from cpu_is, since it checks via features rather than CPUs directly. virtual bool validateCPUSpecificCPUDispatch(StringRef Name) const { return false; } // Get the character to be added for mangling purposes for cpu_specific. virtual char CPUSpecificManglingCharacter(StringRef Name) const { llvm_unreachable( "cpu_specific Multiversioning not implemented on this target"); } // Get the value for the 'tune-cpu' flag for a cpu_specific variant with the // programmer-specified 'Name'. virtual StringRef getCPUSpecificTuneName(StringRef Name) const { llvm_unreachable( "cpu_specific Multiversioning not implemented on this target"); } // Get a list of the features that make up the CPU option for // cpu_specific/cpu_dispatch so that it can be passed to llvm as optimization // options. virtual void getCPUSpecificCPUDispatchFeatures( StringRef Name, llvm::SmallVectorImpl &Features) const { llvm_unreachable( "cpu_specific Multiversioning not implemented on this target"); } // Get the cache line size of a given cpu. This method switches over // the given cpu and returns "std::nullopt" if the CPU is not found. virtual std::optional getCPUCacheLineSize() const { return std::nullopt; } // Returns maximal number of args passed in registers. unsigned getRegParmMax() const { assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); return RegParmMax; } /// Whether the target supports thread-local storage. bool isTLSSupported() const { return TLSSupported; } /// Return the maximum alignment (in bits) of a TLS variable /// /// Gets the maximum alignment (in bits) of a TLS variable on this target. /// Returns zero if there is no such constraint. unsigned getMaxTLSAlign() const { return MaxTLSAlign; } /// Whether target supports variable-length arrays. bool isVLASupported() const { return VLASupported; } /// Whether the target supports SEH __try. bool isSEHTrySupported() const { return getTriple().isOSWindows() && (getTriple().isX86() || getTriple().getArch() == llvm::Triple::aarch64); } /// Return true if {|} are normal characters in the asm string. /// /// If this returns false (the default), then {abc|xyz} is syntax /// that says that when compiling for asm variant #0, "abc" should be /// generated, but when compiling for asm variant #1, "xyz" should be /// generated. bool hasNoAsmVariants() const { return NoAsmVariants; } /// Return the register number that __builtin_eh_return_regno would /// return with the specified argument. /// This corresponds with TargetLowering's getExceptionPointerRegister /// and getExceptionSelectorRegister in the backend. virtual int getEHDataRegisterNumber(unsigned RegNo) const { return -1; } /// Return the section to use for C++ static initialization functions. virtual const char *getStaticInitSectionSpecifier() const { return nullptr; } const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; } unsigned getTargetAddressSpace(LangAS AS) const { if (isTargetAddressSpace(AS)) return toTargetAddressSpace(AS); return getAddressSpaceMap()[(unsigned)AS]; } /// Map from the address space field in builtin description strings to the /// language address space. virtual LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const { return getLangASFromTargetAS(AS); } /// Map from the address space field in builtin description strings to the /// language address space. virtual LangAS getCUDABuiltinAddressSpace(unsigned AS) const { return getLangASFromTargetAS(AS); } /// Return an AST address space which can be used opportunistically /// for constant global memory. It must be possible to convert pointers into /// this address space to LangAS::Default. If no such address space exists, /// this may return std::nullopt, and such optimizations will be disabled. virtual std::optional getConstantAddressSpace() const { return LangAS::Default; } // access target-specific GPU grid values that must be consistent between // host RTL (plugin), deviceRTL and clang. virtual const llvm::omp::GV &getGridValue() const { llvm_unreachable("getGridValue not implemented on this target"); } /// Retrieve the name of the platform as it is used in the /// availability attribute. StringRef getPlatformName() const { return PlatformName; } /// Retrieve the minimum desired version of the platform, to /// which the program should be compiled. VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; } bool isBigEndian() const { return BigEndian; } bool isLittleEndian() const { return !BigEndian; } /// Whether the option -fextend-arguments={32,64} is supported on the target. virtual bool supportsExtendIntArgs() const { return false; } /// Controls if __arithmetic_fence is supported in the targeted backend. virtual bool checkArithmeticFenceSupported() const { return false; } /// Gets the default calling convention for the given target and /// declaration context. virtual CallingConv getDefaultCallingConv() const { // Not all targets will specify an explicit calling convention that we can // express. This will always do the right thing, even though it's not // an explicit calling convention. return CC_C; } enum CallingConvCheckResult { CCCR_OK, CCCR_Warning, CCCR_Ignore, CCCR_Error, }; /// Determines whether a given calling convention is valid for the /// target. A calling convention can either be accepted, produce a warning /// and be substituted with the default calling convention, or (someday) /// produce an error (such as using thiscall on a non-instance function). virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { switch (CC) { default: return CCCR_Warning; case CC_C: return CCCR_OK; } } enum CallingConvKind { CCK_Default, CCK_ClangABI4OrPS4, CCK_MicrosoftWin64 }; virtual CallingConvKind getCallingConvKind(bool ClangABICompat4) const; /// Controls whether explicitly defaulted (`= default`) special member /// functions disqualify something from being POD-for-the-purposes-of-layout. /// Historically, Clang didn't consider these acceptable for POD, but GCC /// does. So in newer Clang ABIs they are acceptable for POD to be compatible /// with GCC/Itanium ABI, and remains disqualifying for targets that need /// Clang backwards compatibility rather than GCC/Itanium ABI compatibility. virtual bool areDefaultedSMFStillPOD(const LangOptions&) const; /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp. virtual bool hasSjLjLowering() const { return false; } /// Check if the target supports CFProtection branch. virtual bool checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const; /// Check if the target supports CFProtection return. virtual bool checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const; /// Whether target allows to overalign ABI-specified preferred alignment virtual bool allowsLargerPreferedTypeAlignment() const { return true; } /// Whether target defaults to the `power` alignment rules of AIX. virtual bool defaultsToAIXPowerAlignment() const { return false; } /// Set supported OpenCL extensions and optional core features. virtual void setSupportedOpenCLOpts() {} virtual void supportAllOpenCLOpts(bool V = true) { #define OPENCLEXTNAME(Ext) \ setFeatureEnabled(getTargetOpts().OpenCLFeaturesMap, #Ext, V); #include "clang/Basic/OpenCLExtensions.def" } /// Set supported OpenCL extensions as written on command line virtual void setCommandLineOpenCLOpts() { for (const auto &Ext : getTargetOpts().OpenCLExtensionsAsWritten) { bool IsPrefixed = (Ext[0] == '+' || Ext[0] == '-'); std::string Name = IsPrefixed ? Ext.substr(1) : Ext; bool V = IsPrefixed ? Ext[0] == '+' : true; if (Name == "all") { supportAllOpenCLOpts(V); continue; } getTargetOpts().OpenCLFeaturesMap[Name] = V; } } /// Get supported OpenCL extensions and optional core features. llvm::StringMap &getSupportedOpenCLOpts() { return getTargetOpts().OpenCLFeaturesMap; } /// Get const supported OpenCL extensions and optional core features. const llvm::StringMap &getSupportedOpenCLOpts() const { return getTargetOpts().OpenCLFeaturesMap; } /// Get address space for OpenCL type. virtual LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const; /// \returns Target specific vtbl ptr address space. virtual unsigned getVtblPtrAddressSpace() const { return 0; } /// \returns If a target requires an address within a target specific address /// space \p AddressSpace to be converted in order to be used, then return the /// corresponding target specific DWARF address space. /// /// \returns Otherwise return std::nullopt and no conversion will be emitted /// in the DWARF. virtual std::optional getDWARFAddressSpace(unsigned AddressSpace) const { return std::nullopt; } /// \returns The version of the SDK which was used during the compilation if /// one was specified, or an empty version otherwise. const llvm::VersionTuple &getSDKVersion() const { return getTargetOpts().SDKVersion; } /// Check the target is valid after it is fully initialized. virtual bool validateTarget(DiagnosticsEngine &Diags) const { return true; } /// Check that OpenCL target has valid options setting based on OpenCL /// version. virtual bool validateOpenCLTarget(const LangOptions &Opts, DiagnosticsEngine &Diags) const; virtual void setAuxTarget(const TargetInfo *Aux) {} /// Whether target allows debuginfo types for decl only variables/functions. virtual bool allowDebugInfoForExternalRef() const { return false; } /// Returns the darwin target variant triple, the variant of the deployment /// target for which the code is being compiled. const llvm::Triple *getDarwinTargetVariantTriple() const { return DarwinTargetVariantTriple ? &*DarwinTargetVariantTriple : nullptr; } /// Returns the version of the darwin target variant SDK which was used during /// the compilation if one was specified, or an empty version otherwise. const std::optional getDarwinTargetVariantSDKVersion() const { return !getTargetOpts().DarwinTargetVariantSDKVersion.empty() ? getTargetOpts().DarwinTargetVariantSDKVersion : std::optional(); } /// Whether to support HIP image/texture API's. virtual bool hasHIPImageSupport() const { return true; } protected: /// Copy type and layout related info. void copyAuxTarget(const TargetInfo *Aux); virtual uint64_t getPointerWidthV(LangAS AddrSpace) const { return PointerWidth; } virtual uint64_t getPointerAlignV(LangAS AddrSpace) const { return PointerAlign; } virtual enum IntType getPtrDiffTypeV(LangAS AddrSpace) const { return PtrDiffType; } virtual ArrayRef getGCCRegNames() const = 0; virtual ArrayRef getGCCRegAliases() const = 0; virtual ArrayRef getGCCAddlRegNames() const { return std::nullopt; } private: // Assert the values for the fractional and integral bits for each fixed point // type follow the restrictions given in clause 6.2.6.3 of N1169. void CheckFixedPointBits() const; }; } // end namespace clang #endif