blob: e1ef7454f01669c4ecff7f1998275a0b2512ed71 [file] [log] [blame]
//===--- 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/APSInt.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 <cassert>
#include <optional>
#include <string>
#include <vector>
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<std::string> 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<TargetInfo> {
std::shared_ptr<TargetOptions> 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<FloatModeKind>;
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;
LLVM_PREFERRED_TYPE(bool)
unsigned HasUnalignedAccess : 1;
unsigned ARMCDECoprocMask : 8;
unsigned MaxOpenCLWorkGroupSize;
std::optional<unsigned> MaxBitIntWidth;
std::optional<llvm::Triple> 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<TargetOptions> &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<size_t>(*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. If \param
/// HasNonWeakDef is true, this concerns a VarDecl which has a definition
/// in current translation unit and that is not weak.
virtual unsigned getMinGlobalAlign(uint64_t Size, bool HasNonWeakDef) 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;
}
/// Return true iff unaligned accesses are a single instruction (rather than
/// a synthesized sequence).
bool hasUnalignedAccess() const { return HasUnalignedAccess; }
/// Return true iff unaligned accesses are cheap. This affects placement and
/// size of bitfield loads/stores. (Not the ABI-mandated placement of
/// the bitfields themselves.)
bool hasCheapUnalignedBitFieldAccess() const {
// Simply forward to the unaligned access getter.
return hasUnalignedAccess();
}
/// \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<Builtin::Info> getTargetBuiltins() const = 0;
/// Returns target-specific min and max values VScale_Range.
virtual std::optional<std::pair<unsigned, unsigned>>
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<int, 4> 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<int> 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<ConstraintInfo> OutputConstraints,
ConstraintInfo &info) const;
virtual bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
StringRef /*Constraint*/,
unsigned /*Size*/) const {
return true;
}
virtual bool validateInputSize(const llvm::StringMap<bool> &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<ConstraintInfo> 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<std::string> 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<std::string> 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<bool> &Features,
DiagnosticsEngine &Diags, StringRef CPU,
const std::vector<std::string> &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<StringRef> &Values) const {}
/// Fill a SmallVectorImpl with the valid values for tuning CPU.
virtual void fillValidTuneCPUList(SmallVectorImpl<StringRef> &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<bool> &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<bool> &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::SignReturnAddressKeyKind SignKey;
bool BranchTargetEnforcement;
bool BranchProtectionPAuthLR;
bool GuardedControlStack;
BranchProtectionInfo() = default;
const char *getSignReturnAddrStr() const {
switch (SignReturnAddr) {
case LangOptions::SignReturnAddressScopeKind::None:
return "none";
case LangOptions::SignReturnAddressScopeKind::NonLeaf:
return "non-leaf";
case LangOptions::SignReturnAddressScopeKind::All:
return "all";
}
llvm_unreachable("Unexpected SignReturnAddressScopeKind");
}
const char *getSignKeyStr() const {
switch (SignKey) {
case LangOptions::SignReturnAddressKeyKind::AKey:
return "a_key";
case LangOptions::SignReturnAddressKeyKind::BKey:
return "b_key";
}
llvm_unreachable("Unexpected SignReturnAddressKeyKind");
}
};
/// 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<std::string> &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());
}
// Identify whether this target supports __builtin_cpu_supports and
// __builtin_cpu_is.
virtual bool supportsCpuSupports() const { return false; }
virtual bool supportsCpuIs() const { return false; }
virtual bool supportsCpuInit() const { return false; }
// 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<StringRef> &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<unsigned> 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];
}
/// Determine whether the given pointer-authentication key is valid.
///
/// The value has been coerced to type 'int'.
virtual bool validatePointerAuthKey(const llvm::APSInt &value) const;
/// 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<LangAS> 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<bool> &getSupportedOpenCLOpts() {
return getTargetOpts().OpenCLFeaturesMap;
}
/// Get const supported OpenCL extensions and optional core features.
const llvm::StringMap<bool> &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<unsigned> 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<VersionTuple> getDarwinTargetVariantSDKVersion() const {
return !getTargetOpts().DarwinTargetVariantSDKVersion.empty()
? getTargetOpts().DarwinTargetVariantSDKVersion
: std::optional<VersionTuple>();
}
/// 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<const char *> getGCCRegNames() const = 0;
virtual ArrayRef<GCCRegAlias> getGCCRegAliases() const = 0;
virtual ArrayRef<AddlRegName> 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