forked from OSchip/llvm-project
[ARM] Add __bf16 as new Bfloat16 C Type
Summary: This patch upstreams support for a new storage only bfloat16 C type. This type is used to implement primitive support for bfloat16 data, in line with the Bfloat16 extension of the Armv8.6-a architecture, as detailed here: https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-architecture-developments-armv8-6-a The bfloat type, and its properties are specified in the Arm Architecture Reference Manual: https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile In detail this patch: - introduces an opaque, storage-only C-type __bf16, which introduces a new bfloat IR type. This is part of a patch series, starting with command-line and Bfloat16 assembly support. The subsequent patches will upstream intrinsics support for BFloat16, followed by Matrix Multiplication and the remaining Virtualization features of the armv8.6-a architecture. The following people contributed to this patch: - Luke Cheeseman - Momchil Velikov - Alexandros Lamprineas - Luke Geeson - Simon Tatham - Ties Stuij Reviewers: SjoerdMeijer, rjmccall, rsmith, liutianle, RKSimon, craig.topper, jfb, LukeGeeson, fpetrogalli Reviewed By: SjoerdMeijer Subscribers: labrinea, majnemer, asmith, dexonsmith, kristof.beyls, arphaman, danielkiss, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D76077
This commit is contained in:
parent
04fb2b6123
commit
ecd682bbf5
|
@ -516,8 +516,8 @@ float matrices and add the result to a third 4x4 matrix.
|
|||
Half-Precision Floating Point
|
||||
=============================
|
||||
|
||||
Clang supports two half-precision (16-bit) floating point types: ``__fp16`` and
|
||||
``_Float16``. These types are supported in all language modes.
|
||||
Clang supports three half-precision (16-bit) floating point types: ``__fp16``,
|
||||
``_Float16`` and ``__bf16``. These types are supported in all language modes.
|
||||
|
||||
``__fp16`` is supported on every target, as it is purely a storage format; see below.
|
||||
``_Float16`` is currently only supported on the following targets, with further
|
||||
|
@ -529,6 +529,12 @@ targets pending ABI standardization:
|
|||
|
||||
``_Float16`` will be supported on more targets as they define ABIs for it.
|
||||
|
||||
``__bf16`` is purely a storage format; it is currently only supported on the following targets:
|
||||
* 32-bit ARM
|
||||
* 64-bit ARM (AArch64)
|
||||
|
||||
The ``__bf16`` type is only available when supported in hardware.
|
||||
|
||||
``__fp16`` is a storage and interchange format only. This means that values of
|
||||
``__fp16`` are immediately promoted to (at least) ``float`` when used in arithmetic
|
||||
operations, so that e.g. the result of adding two ``__fp16`` values has type ``float``.
|
||||
|
|
|
@ -3253,8 +3253,9 @@ enum CXTypeKind {
|
|||
CXType_UShortAccum = 36,
|
||||
CXType_UAccum = 37,
|
||||
CXType_ULongAccum = 38,
|
||||
CXType_BFloat16 = 39,
|
||||
CXType_FirstBuiltin = CXType_Void,
|
||||
CXType_LastBuiltin = CXType_ULongAccum,
|
||||
CXType_LastBuiltin = CXType_BFloat16,
|
||||
|
||||
CXType_Complex = 100,
|
||||
CXType_Pointer = 101,
|
||||
|
|
|
@ -964,6 +964,7 @@ public:
|
|||
CanQualType SatUnsignedShortFractTy, SatUnsignedFractTy,
|
||||
SatUnsignedLongFractTy;
|
||||
CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
|
||||
CanQualType BFloat16Ty;
|
||||
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
|
||||
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
CanQualType Float128ComplexTy;
|
||||
|
|
|
@ -212,6 +212,9 @@ FLOATING_TYPE(LongDouble, LongDoubleTy)
|
|||
// '_Float16'
|
||||
FLOATING_TYPE(Float16, HalfTy)
|
||||
|
||||
// '__bf16'
|
||||
FLOATING_TYPE(BFloat16, BFloat16Ty)
|
||||
|
||||
// '__float128'
|
||||
FLOATING_TYPE(Float128, Float128Ty)
|
||||
|
||||
|
|
|
@ -2008,6 +2008,7 @@ public:
|
|||
bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
|
||||
bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
|
||||
bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
|
||||
bool isBFloat16Type() const;
|
||||
bool isFloat128Type() const;
|
||||
bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
|
||||
bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
|
||||
|
@ -6931,6 +6932,10 @@ inline bool Type::isFloat16Type() const {
|
|||
return isSpecificBuiltinType(BuiltinType::Float16);
|
||||
}
|
||||
|
||||
inline bool Type::isBFloat16Type() const {
|
||||
return isSpecificBuiltinType(BuiltinType::BFloat16);
|
||||
}
|
||||
|
||||
inline bool Type::isFloat128Type() const {
|
||||
return isSpecificBuiltinType(BuiltinType::Float128);
|
||||
}
|
||||
|
|
|
@ -8121,6 +8121,8 @@ def warn_bad_function_cast : Warning<
|
|||
InGroup<BadFunctionCast>, DefaultIgnore;
|
||||
def err_cast_pointer_to_non_pointer_int : Error<
|
||||
"pointer cannot be cast to type %0">;
|
||||
def err_cast_to_bfloat16 : Error<"cannot type-cast to __bf16">;
|
||||
def err_cast_from_bfloat16 : Error<"cannot type-cast from __bf16">;
|
||||
def err_typecheck_expect_scalar_operand : Error<
|
||||
"operand of type %0 where arithmetic or pointer type is required">;
|
||||
def err_typecheck_cond_incompatible_operands : Error<
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace clang {
|
|||
TST_Float16, // C11 extension ISO/IEC TS 18661-3
|
||||
TST_Accum, // ISO/IEC JTC1 SC22 WG14 N1169 Extension
|
||||
TST_Fract,
|
||||
TST_BFloat16,
|
||||
TST_float,
|
||||
TST_double,
|
||||
TST_float128,
|
||||
|
|
|
@ -142,7 +142,8 @@ namespace clang {
|
|||
Poly128,
|
||||
Float16,
|
||||
Float32,
|
||||
Float64
|
||||
Float64,
|
||||
BFloat16
|
||||
};
|
||||
|
||||
NeonTypeFlags(unsigned F) : Flags(F) {}
|
||||
|
|
|
@ -59,6 +59,7 @@ struct TransferrableTargetInfo {
|
|||
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;
|
||||
|
@ -100,8 +101,8 @@ struct TransferrableTargetInfo {
|
|||
unsigned short MaxVectorAlign;
|
||||
unsigned short MaxTLSAlign;
|
||||
|
||||
const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat,
|
||||
*LongDoubleFormat, *Float128Format;
|
||||
const llvm::fltSemantics *HalfFormat, *BFloat16Format, *FloatFormat,
|
||||
*DoubleFormat, *LongDoubleFormat, *Float128Format;
|
||||
|
||||
///===---- Target Data Type Query Methods -------------------------------===//
|
||||
enum IntType {
|
||||
|
@ -188,6 +189,7 @@ protected:
|
|||
// LLVM IR type.
|
||||
bool HasFloat128;
|
||||
bool HasFloat16;
|
||||
bool HasBFloat16;
|
||||
|
||||
unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
|
||||
unsigned short SimdDefaultAlign;
|
||||
|
@ -567,6 +569,9 @@ public:
|
|||
/// 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; }
|
||||
|
||||
/// Return the alignment that is suitable for storing any
|
||||
/// object with a fundamental alignment requirement.
|
||||
unsigned getSuitableAlign() const { return SuitableAlign; }
|
||||
|
@ -615,6 +620,11 @@ public:
|
|||
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; }
|
||||
|
@ -642,6 +652,11 @@ public:
|
|||
/// Return the mangled code of __float128.
|
||||
virtual const char *getFloat128Mangling() const { return "g"; }
|
||||
|
||||
/// Return the mangled code of bfloat.
|
||||
virtual const char *getBFloat16Mangling() const {
|
||||
llvm_unreachable("bfloat not implemented on this target");
|
||||
}
|
||||
|
||||
/// Return the value for the C99 FLT_EVAL_METHOD macro.
|
||||
virtual unsigned getFloatEvalMethod() const { return 0; }
|
||||
|
||||
|
|
|
@ -591,6 +591,7 @@ KEYWORD(__bool , KEYALTIVEC|KEYZVECTOR)
|
|||
|
||||
// ARM NEON extensions.
|
||||
ALIAS("__fp16", half , KEYALL)
|
||||
KEYWORD(__bf16 , KEYALL)
|
||||
|
||||
// OpenCL Extension.
|
||||
KEYWORD(half , HALFSUPPORT)
|
||||
|
|
|
@ -281,6 +281,7 @@ public:
|
|||
static const TST TST_int128 = clang::TST_int128;
|
||||
static const TST TST_extint = clang::TST_extint;
|
||||
static const TST TST_half = clang::TST_half;
|
||||
static const TST TST_BFloat16 = clang::TST_BFloat16;
|
||||
static const TST TST_float = clang::TST_float;
|
||||
static const TST TST_double = clang::TST_double;
|
||||
static const TST TST_float16 = clang::TST_Float16;
|
||||
|
|
|
@ -1060,7 +1060,10 @@ namespace serialization {
|
|||
/// A placeholder type for incomplete matrix index operations.
|
||||
PREDEF_TYPE_INCOMPLETE_MATRIX_IDX = 72,
|
||||
|
||||
/// OpenCL image types with auto numeration
|
||||
/// \brief The '__bf16' type
|
||||
PREDEF_TYPE_BFLOAT16_ID = 73,
|
||||
|
||||
/// OpenCL image types with auto numeration
|
||||
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
|
||||
PREDEF_TYPE_##Id##_ID,
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
using namespace clang;
|
||||
|
||||
enum FloatingRank {
|
||||
Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
|
||||
BFloat16Rank, Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
|
||||
};
|
||||
|
||||
/// \returns location that is relevant when searching for Doc comments related
|
||||
|
@ -1448,6 +1448,8 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
|
|||
// half type (OpenCL 6.1.1.1) / ARM NEON __fp16
|
||||
InitBuiltinType(HalfTy, BuiltinType::Half);
|
||||
|
||||
InitBuiltinType(BFloat16Ty, BuiltinType::BFloat16);
|
||||
|
||||
// Builtin type used to help define __builtin_va_list.
|
||||
VaListTagDecl = nullptr;
|
||||
|
||||
|
@ -1651,6 +1653,8 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
|
|||
switch (T->castAs<BuiltinType>()->getKind()) {
|
||||
default:
|
||||
llvm_unreachable("Not a floating point type!");
|
||||
case BuiltinType::BFloat16:
|
||||
return Target->getBFloat16Format();
|
||||
case BuiltinType::Float16:
|
||||
case BuiltinType::Half:
|
||||
return Target->getHalfFormat();
|
||||
|
@ -2045,6 +2049,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
|
|||
Width = Target->getLongFractWidth();
|
||||
Align = Target->getLongFractAlign();
|
||||
break;
|
||||
case BuiltinType::BFloat16:
|
||||
Width = Target->getBFloat16Width();
|
||||
Align = Target->getBFloat16Align();
|
||||
break;
|
||||
case BuiltinType::Float16:
|
||||
case BuiltinType::Half:
|
||||
if (Target->hasFloat16Type() || !getLangOpts().OpenMP ||
|
||||
|
@ -5984,6 +5992,7 @@ static FloatingRank getFloatingRank(QualType T) {
|
|||
case BuiltinType::Double: return DoubleRank;
|
||||
case BuiltinType::LongDouble: return LongDoubleRank;
|
||||
case BuiltinType::Float128: return Float128Rank;
|
||||
case BuiltinType::BFloat16: return BFloat16Rank;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5996,6 +6005,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
|
|||
FloatingRank EltRank = getFloatingRank(Size);
|
||||
if (Domain->isComplexType()) {
|
||||
switch (EltRank) {
|
||||
case BFloat16Rank: llvm_unreachable("Complex bfloat16 is not supported");
|
||||
case Float16Rank:
|
||||
case HalfRank: llvm_unreachable("Complex half is not supported");
|
||||
case FloatRank: return FloatComplexTy;
|
||||
|
@ -6008,6 +6018,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
|
|||
assert(Domain->isRealFloatingType() && "Unknown domain!");
|
||||
switch (EltRank) {
|
||||
case Float16Rank: return HalfTy;
|
||||
case BFloat16Rank: return BFloat16Ty;
|
||||
case HalfRank: return HalfTy;
|
||||
case FloatRank: return FloatTy;
|
||||
case DoubleRank: return DoubleTy;
|
||||
|
@ -6985,6 +6996,7 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C,
|
|||
case BuiltinType::LongDouble: return 'D';
|
||||
case BuiltinType::NullPtr: return '*'; // like char*
|
||||
|
||||
case BuiltinType::BFloat16:
|
||||
case BuiltinType::Float16:
|
||||
case BuiltinType::Float128:
|
||||
case BuiltinType::Half:
|
||||
|
@ -9892,6 +9904,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
|
|||
// Read the base type.
|
||||
switch (*Str++) {
|
||||
default: llvm_unreachable("Unknown builtin type letter!");
|
||||
case 'y':
|
||||
assert(HowLong == 0 && !Signed && !Unsigned &&
|
||||
"Bad modifiers used with 'y'!");
|
||||
Type = Context.BFloat16Ty;
|
||||
break;
|
||||
case 'v':
|
||||
assert(HowLong == 0 && !Signed && !Unsigned &&
|
||||
"Bad modifiers used with 'v'!");
|
||||
|
|
|
@ -2764,6 +2764,11 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
|
|||
Out << TI->getFloat128Mangling();
|
||||
break;
|
||||
}
|
||||
case BuiltinType::BFloat16: {
|
||||
const TargetInfo *TI = &getASTContext().getTargetInfo();
|
||||
Out << TI->getBFloat16Mangling();
|
||||
break;
|
||||
}
|
||||
case BuiltinType::NullPtr:
|
||||
Out << "Dn";
|
||||
break;
|
||||
|
@ -3179,7 +3184,8 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
|
|||
case BuiltinType::ULongLong: EltName = "uint64_t"; break;
|
||||
case BuiltinType::Double: EltName = "float64_t"; break;
|
||||
case BuiltinType::Float: EltName = "float32_t"; break;
|
||||
case BuiltinType::Half: EltName = "float16_t";break;
|
||||
case BuiltinType::Half: EltName = "float16_t"; break;
|
||||
case BuiltinType::BFloat16: EltName = "bfloat16_t"; break;
|
||||
default:
|
||||
llvm_unreachable("unexpected Neon vector element type");
|
||||
}
|
||||
|
@ -3231,6 +3237,8 @@ static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) {
|
|||
return "Float32";
|
||||
case BuiltinType::Double:
|
||||
return "Float64";
|
||||
case BuiltinType::BFloat16:
|
||||
return "BFloat16";
|
||||
default:
|
||||
llvm_unreachable("Unexpected vector element base type");
|
||||
}
|
||||
|
|
|
@ -2114,6 +2114,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
|
|||
case BuiltinType::SatUShortFract:
|
||||
case BuiltinType::SatUFract:
|
||||
case BuiltinType::SatULongFract:
|
||||
case BuiltinType::BFloat16:
|
||||
case BuiltinType::Float128: {
|
||||
DiagnosticsEngine &Diags = Context.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(
|
||||
|
|
|
@ -486,6 +486,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
|
|||
case BuiltinType::OMPArraySection:
|
||||
case BuiltinType::OMPArrayShaping:
|
||||
case BuiltinType::OMPIterator:
|
||||
case BuiltinType::BFloat16:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -752,6 +752,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
|
|||
case BuiltinType::UInt128:
|
||||
case BuiltinType::Int128:
|
||||
case BuiltinType::Half:
|
||||
case BuiltinType::BFloat16:
|
||||
case BuiltinType::Float16:
|
||||
case BuiltinType::Float128:
|
||||
case BuiltinType::ShortAccum:
|
||||
|
|
|
@ -2137,7 +2137,8 @@ bool Type::isRealType() const {
|
|||
bool Type::isArithmeticType() const {
|
||||
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::Float128;
|
||||
BT->getKind() <= BuiltinType::Float128 &&
|
||||
BT->getKind() != BuiltinType::BFloat16;
|
||||
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
|
||||
// GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
|
||||
// If a body isn't seen by the time we get here, return false.
|
||||
|
@ -2922,6 +2923,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
|
|||
return "unsigned __int128";
|
||||
case Half:
|
||||
return Policy.Half ? "half" : "__fp16";
|
||||
case BFloat16:
|
||||
return "__bf16";
|
||||
case Float:
|
||||
return "float";
|
||||
case Double:
|
||||
|
|
|
@ -375,6 +375,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
|
|||
case BuiltinType::SatUShortFract:
|
||||
case BuiltinType::SatUFract:
|
||||
case BuiltinType::SatULongFract:
|
||||
case BuiltinType::BFloat16:
|
||||
llvm_unreachable("Builtin type needs extra local data!");
|
||||
// Fall through, if the impossible happens.
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
|
|||
HasLegalHalfType = false;
|
||||
HasFloat128 = false;
|
||||
HasFloat16 = false;
|
||||
HasBFloat16 = false;
|
||||
PointerWidth = PointerAlign = 32;
|
||||
BoolWidth = BoolAlign = 8;
|
||||
IntWidth = IntAlign = 32;
|
||||
|
|
|
@ -70,6 +70,9 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
|
|||
LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
|
||||
LongDoubleFormat = &llvm::APFloat::IEEEquad();
|
||||
|
||||
BFloat16Width = BFloat16Align = 16;
|
||||
BFloat16Format = &llvm::APFloat::BFloat();
|
||||
|
||||
// Make __builtin_ms_va_list available.
|
||||
HasBuiltinMSVaList = true;
|
||||
|
||||
|
@ -360,6 +363,7 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
|||
HasMTE = false;
|
||||
HasTME = false;
|
||||
HasMatMul = false;
|
||||
HasBFloat16 = false;
|
||||
ArchKind = llvm::AArch64::ArchKind::ARMV8A;
|
||||
|
||||
for (const auto &Feature : Features) {
|
||||
|
@ -397,6 +401,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
|||
HasTME = true;
|
||||
if (Feature == "+i8mm")
|
||||
HasMatMul = true;
|
||||
if (Feature == "+bf16")
|
||||
HasBFloat16 = true;
|
||||
}
|
||||
|
||||
setDataLayout();
|
||||
|
|
|
@ -119,6 +119,7 @@ public:
|
|||
|
||||
int getEHDataRegisterNumber(unsigned RegNo) const override;
|
||||
|
||||
const char *getBFloat16Mangling() const override { return "u6__bf16"; };
|
||||
bool hasInt128Type() const override;
|
||||
|
||||
bool hasExtIntType() const override { return true; }
|
||||
|
|
|
@ -25,6 +25,9 @@ void ARMTargetInfo::setABIAAPCS() {
|
|||
IsAAPCS = true;
|
||||
|
||||
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
|
||||
BFloat16Width = BFloat16Align = 16;
|
||||
BFloat16Format = &llvm::APFloat::BFloat();
|
||||
|
||||
const llvm::Triple &T = getTriple();
|
||||
|
||||
bool IsNetBSD = T.isOSNetBSD();
|
||||
|
@ -74,6 +77,8 @@ void ARMTargetInfo::setABIAPCS(bool IsAAPCS16) {
|
|||
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
|
||||
else
|
||||
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
|
||||
BFloat16Width = BFloat16Align = 16;
|
||||
BFloat16Format = &llvm::APFloat::BFloat();
|
||||
|
||||
WCharType = SignedInt;
|
||||
|
||||
|
@ -428,6 +433,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
|||
HasMatMul = 0;
|
||||
HasFloat16 = true;
|
||||
ARMCDECoprocMask = 0;
|
||||
HasBFloat16 = false;
|
||||
|
||||
// This does not diagnose illegal cases like having both
|
||||
// "+vfpv2" and "+vfpv3" or having "+neon" and "-fp64".
|
||||
|
@ -498,6 +504,8 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
|||
Feature <= "+cdecp7") {
|
||||
unsigned Coproc = Feature.back() - '0';
|
||||
ARMCDECoprocMask |= (1U << Coproc);
|
||||
} else if (Feature == "+bf16") {
|
||||
HasBFloat16 = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,6 +555,10 @@ bool ARMTargetInfo::hasFeature(StringRef Feature) const {
|
|||
.Default(false);
|
||||
}
|
||||
|
||||
bool ARMTargetInfo::hasBFloat16Type() const {
|
||||
return HasBFloat16 && !SoftFloat;
|
||||
}
|
||||
|
||||
bool ARMTargetInfo::isValidCPUName(StringRef Name) const {
|
||||
return Name == "generic" ||
|
||||
llvm::ARM::parseCPUArch(Name) != llvm::ARM::ArchKind::INVALID;
|
||||
|
|
|
@ -137,6 +137,8 @@ public:
|
|||
|
||||
bool hasFeature(StringRef Feature) const override;
|
||||
|
||||
bool hasBFloat16Type() const override;
|
||||
|
||||
bool isValidCPUName(StringRef Name) const override;
|
||||
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
|
||||
|
||||
|
@ -184,6 +186,8 @@ public:
|
|||
bool hasSjLjLowering() const override;
|
||||
|
||||
bool hasExtIntType() const override { return true; }
|
||||
|
||||
const char *getBFloat16Mangling() const override { return "u6__bf16"; };
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo {
|
||||
|
|
|
@ -60,6 +60,8 @@ namespace swiftcall {
|
|||
|
||||
virtual bool supportsSwift() const { return false; }
|
||||
|
||||
virtual bool allowBFloatArgsAndRet() const { return false; }
|
||||
|
||||
CodeGen::CGCXXABI &getCXXABI() const;
|
||||
ASTContext &getContext() const;
|
||||
llvm::LLVMContext &getVMContext() const;
|
||||
|
|
|
@ -4480,8 +4480,9 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
|
|||
|
||||
static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
|
||||
NeonTypeFlags TypeFlags,
|
||||
bool HasLegalHalfType=true,
|
||||
bool V1Ty=false) {
|
||||
bool HasLegalHalfType = true,
|
||||
bool V1Ty = false,
|
||||
bool AllowBFloatArgsAndRet = true) {
|
||||
int IsQuad = TypeFlags.isQuad();
|
||||
switch (TypeFlags.getEltType()) {
|
||||
case NeonTypeFlags::Int8:
|
||||
|
@ -4490,6 +4491,11 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
|
|||
case NeonTypeFlags::Int16:
|
||||
case NeonTypeFlags::Poly16:
|
||||
return llvm::FixedVectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad));
|
||||
case NeonTypeFlags::BFloat16:
|
||||
if (AllowBFloatArgsAndRet)
|
||||
return llvm::FixedVectorType::get(CGF->BFloatTy, V1Ty ? 1 : (4 << IsQuad));
|
||||
else
|
||||
return llvm::FixedVectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad));
|
||||
case NeonTypeFlags::Float16:
|
||||
if (HasLegalHalfType)
|
||||
return llvm::FixedVectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad));
|
||||
|
@ -5505,8 +5511,11 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
|
|||
bool Usgn = Type.isUnsigned();
|
||||
bool Quad = Type.isQuad();
|
||||
const bool HasLegalHalfType = getTarget().hasLegalHalfType();
|
||||
const bool AllowBFloatArgsAndRet =
|
||||
getTargetHooks().getABIInfo().allowBFloatArgsAndRet();
|
||||
|
||||
llvm::VectorType *VTy = GetNeonType(this, Type, HasLegalHalfType);
|
||||
llvm::VectorType *VTy = GetNeonType(this, Type, HasLegalHalfType, false,
|
||||
AllowBFloatArgsAndRet);
|
||||
llvm::Type *Ty = VTy;
|
||||
if (!Ty)
|
||||
return nullptr;
|
||||
|
@ -6975,7 +6984,9 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
|
|||
bool rightShift = false;
|
||||
|
||||
llvm::VectorType *VTy = GetNeonType(this, Type,
|
||||
getTarget().hasLegalHalfType());
|
||||
getTarget().hasLegalHalfType(),
|
||||
false,
|
||||
getTarget().hasBFloat16Type());
|
||||
llvm::Type *Ty = VTy;
|
||||
if (!Ty)
|
||||
return nullptr;
|
||||
|
|
|
@ -772,6 +772,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
|
|||
case BuiltinType::Float:
|
||||
case BuiltinType::LongDouble:
|
||||
case BuiltinType::Float16:
|
||||
case BuiltinType::BFloat16:
|
||||
case BuiltinType::Float128:
|
||||
case BuiltinType::Double:
|
||||
// FIXME: For targets where long double and __float128 have the same size,
|
||||
|
|
|
@ -112,6 +112,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
|
|||
Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
|
||||
Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
|
||||
HalfTy = llvm::Type::getHalfTy(LLVMContext);
|
||||
BFloatTy = llvm::Type::getBFloatTy(LLVMContext);
|
||||
FloatTy = llvm::Type::getFloatTy(LLVMContext);
|
||||
DoubleTy = llvm::Type::getDoubleTy(LLVMContext);
|
||||
PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
|
||||
|
|
|
@ -35,8 +35,8 @@ struct CodeGenTypeCache {
|
|||
|
||||
/// i8, i16, i32, and i64
|
||||
llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty;
|
||||
/// float, double
|
||||
llvm::Type *HalfTy, *FloatTy, *DoubleTy;
|
||||
/// half, bfloat, float, double
|
||||
llvm::Type *HalfTy, *BFloatTy, *FloatTy, *DoubleTy;
|
||||
|
||||
/// int
|
||||
llvm::IntegerType *IntTy;
|
||||
|
|
|
@ -300,6 +300,8 @@ static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
|
|||
else
|
||||
return llvm::Type::getInt16Ty(VMContext);
|
||||
}
|
||||
if (&format == &llvm::APFloat::BFloat())
|
||||
return llvm::Type::getBFloatTy(VMContext);
|
||||
if (&format == &llvm::APFloat::IEEEsingle())
|
||||
return llvm::Type::getFloatTy(VMContext);
|
||||
if (&format == &llvm::APFloat::IEEEdouble())
|
||||
|
@ -498,6 +500,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
|
|||
Context.getLangOpts().NativeHalfType ||
|
||||
!Context.getTargetInfo().useFP16ConversionIntrinsics());
|
||||
break;
|
||||
case BuiltinType::BFloat16:
|
||||
case BuiltinType::Float:
|
||||
case BuiltinType::Double:
|
||||
case BuiltinType::LongDouble:
|
||||
|
|
|
@ -3027,6 +3027,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
|
|||
case BuiltinType::SatUShortFract:
|
||||
case BuiltinType::SatUFract:
|
||||
case BuiltinType::SatULongFract:
|
||||
case BuiltinType::BFloat16:
|
||||
return false;
|
||||
|
||||
case BuiltinType::Dependent:
|
||||
|
|
|
@ -5375,6 +5375,10 @@ private:
|
|||
|
||||
bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
|
||||
unsigned elts) const override;
|
||||
|
||||
bool allowBFloatArgsAndRet() const override {
|
||||
return getTarget().hasBFloat16Type();
|
||||
}
|
||||
};
|
||||
|
||||
class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
|
@ -5980,11 +5984,14 @@ public:
|
|||
|
||||
private:
|
||||
ABIKind Kind;
|
||||
bool IsFloatABISoftFP;
|
||||
|
||||
public:
|
||||
ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind)
|
||||
: SwiftABIInfo(CGT), Kind(_Kind) {
|
||||
setCCs();
|
||||
IsFloatABISoftFP = CGT.getCodeGenOpts().FloatABI == "softfp" ||
|
||||
CGT.getCodeGenOpts().FloatABI == ""; // default
|
||||
}
|
||||
|
||||
bool isEABI() const {
|
||||
|
@ -6015,6 +6022,10 @@ public:
|
|||
|
||||
ABIKind getABIKind() const { return Kind; }
|
||||
|
||||
bool allowBFloatArgsAndRet() const override {
|
||||
return !IsFloatABISoftFP && getTarget().hasBFloat16Type();
|
||||
}
|
||||
|
||||
private:
|
||||
ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic,
|
||||
unsigned functionCallConv) const;
|
||||
|
@ -6254,9 +6265,9 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
|
|||
if (isIllegalVectorType(Ty))
|
||||
return coerceIllegalVector(Ty);
|
||||
|
||||
// _Float16 and __fp16 get passed as if it were an int or float, but with
|
||||
// the top 16 bits unspecified. This is not done for OpenCL as it handles the
|
||||
// half type natively, and does not need to interwork with AAPCS code.
|
||||
// _Float16 and __fp16 get passed as if it were an int or float, but
|
||||
// with the top 16 bits unspecified. This is not done for OpenCL as it handles
|
||||
// the half type natively, and does not need to interwork with AAPCS code.
|
||||
if ((Ty->isFloat16Type() || Ty->isHalfType()) &&
|
||||
!getContext().getLangOpts().NativeHalfArgsAndReturns) {
|
||||
llvm::Type *ResType = IsAAPCS_VFP ?
|
||||
|
@ -6265,6 +6276,13 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
|
|||
return ABIArgInfo::getDirect(ResType);
|
||||
}
|
||||
|
||||
// __bf16 gets passed using the bfloat IR type, or using i32 but
|
||||
// with the top 16 bits unspecified.
|
||||
if (Ty->isBFloat16Type() && IsFloatABISoftFP) {
|
||||
llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext());
|
||||
return ABIArgInfo::getDirect(ResType);
|
||||
}
|
||||
|
||||
if (!isAggregateTypeForABI(Ty)) {
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = Ty->getAs<EnumType>()) {
|
||||
|
@ -6458,10 +6476,13 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic,
|
|||
// Large vector types should be returned via memory.
|
||||
if (getContext().getTypeSize(RetTy) > 128)
|
||||
return getNaturalAlignIndirect(RetTy);
|
||||
// FP16 vectors should be converted to integer vectors
|
||||
if (!getTarget().hasLegalHalfType() &&
|
||||
// TODO: FP16/BF16 vectors should be converted to integer vectors
|
||||
// This check is similar to isIllegalVectorType - refactor?
|
||||
if ((!getTarget().hasLegalHalfType() &&
|
||||
(VT->getElementType()->isFloat16Type() ||
|
||||
VT->getElementType()->isHalfType()))
|
||||
VT->getElementType()->isHalfType())) ||
|
||||
(IsFloatABISoftFP &&
|
||||
VT->getElementType()->isBFloat16Type()))
|
||||
return coerceIllegalVector(RetTy);
|
||||
}
|
||||
|
||||
|
@ -6476,6 +6497,15 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic,
|
|||
return ABIArgInfo::getDirect(ResType);
|
||||
}
|
||||
|
||||
// if we're using the softfp float abi, __bf16 get returned as if it were an
|
||||
// int but with the top 16 bits unspecified.
|
||||
if (RetTy->isBFloat16Type()) {
|
||||
llvm::Type *ResType = IsAAPCS_VFP ?
|
||||
llvm::Type::getBFloatTy(getVMContext()) :
|
||||
llvm::Type::getInt32Ty(getVMContext());
|
||||
return ABIArgInfo::getDirect(ResType);
|
||||
}
|
||||
|
||||
if (!isAggregateTypeForABI(RetTy)) {
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
|
||||
|
@ -6562,12 +6592,17 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic,
|
|||
/// isIllegalVector - check whether Ty is an illegal vector type.
|
||||
bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
|
||||
if (const VectorType *VT = Ty->getAs<VectorType> ()) {
|
||||
// On targets that don't support FP16, FP16 is expanded into float, and we
|
||||
// don't want the ABI to depend on whether or not FP16 is supported in
|
||||
// hardware. Thus return false to coerce FP16 vectors into integer vectors.
|
||||
if (!getTarget().hasLegalHalfType() &&
|
||||
// On targets that don't support half, fp16 or bfloat, they are expanded
|
||||
// into float, and we don't want the ABI to depend on whether or not they
|
||||
// are supported in hardware. Thus return false to coerce vectors of these
|
||||
// types into integer vectors.
|
||||
// We do not depend on hasLegalHalfType for bfloat as it is a
|
||||
// separate IR type.
|
||||
if ((!getTarget().hasLegalHalfType() &&
|
||||
(VT->getElementType()->isFloat16Type() ||
|
||||
VT->getElementType()->isHalfType()))
|
||||
VT->getElementType()->isHalfType())) ||
|
||||
(IsFloatABISoftFP &&
|
||||
VT->getElementType()->isBFloat16Type()))
|
||||
return true;
|
||||
if (isAndroid()) {
|
||||
// Android shipped using Clang 3.1, which supported a slightly different
|
||||
|
@ -6619,6 +6654,7 @@ bool ARMABIInfo::containsAnyFP16Vectors(QualType Ty) const {
|
|||
} else {
|
||||
if (const VectorType *VT = Ty->getAs<VectorType>())
|
||||
return (VT->getElementType()->isFloat16Type() ||
|
||||
VT->getElementType()->isBFloat16Type() ||
|
||||
VT->getElementType()->isHalfType());
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ bool FormatToken::isSimpleTypeSpecifier() const {
|
|||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw__Float16:
|
||||
case tok::kw___float128:
|
||||
case tok::kw_wchar_t:
|
||||
|
|
|
@ -753,6 +753,7 @@ void USRGenerator::VisitType(QualType T) {
|
|||
case BuiltinType::SatUShortFract:
|
||||
case BuiltinType::SatUFract:
|
||||
case BuiltinType::SatULongFract:
|
||||
case BuiltinType::BFloat16:
|
||||
IgnoreResults = true;
|
||||
return;
|
||||
case BuiltinType::ObjCId:
|
||||
|
|
|
@ -3842,6 +3842,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
|
||||
DiagID, Policy);
|
||||
break;
|
||||
case tok::kw___bf16:
|
||||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_BFloat16, Loc, PrevSpec,
|
||||
DiagID, Policy);
|
||||
break;
|
||||
case tok::kw_float:
|
||||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
|
||||
DiagID, Policy);
|
||||
|
@ -4942,6 +4946,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
|
|||
case tok::kw_char32_t:
|
||||
case tok::kw_int:
|
||||
case tok::kw__ExtInt:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
|
@ -5023,6 +5028,7 @@ bool Parser::isTypeSpecifierQualifier() {
|
|||
case tok::kw_int:
|
||||
case tok::kw__ExtInt:
|
||||
case tok::kw_half:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw__Accum:
|
||||
|
@ -5190,6 +5196,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
|||
case tok::kw_int:
|
||||
case tok::kw__ExtInt:
|
||||
case tok::kw_half:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw__Accum:
|
||||
|
|
|
@ -1514,6 +1514,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
|||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw__Float16:
|
||||
case tok::kw___float128:
|
||||
case tok::kw_void:
|
||||
|
|
|
@ -2201,6 +2201,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
|
|||
case tok::kw___int128:
|
||||
DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
case tok::kw___bf16:
|
||||
DS.SetTypeSpecType(DeclSpec::TST_BFloat16, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
case tok::kw_half:
|
||||
DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
|
|
|
@ -1640,6 +1640,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
|||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw__Float16:
|
||||
case tok::kw___float128:
|
||||
case tok::kw_void:
|
||||
|
@ -1753,6 +1754,7 @@ bool Parser::isCXXDeclarationSpecifierAType() {
|
|||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw__Float16:
|
||||
case tok::kw___float128:
|
||||
case tok::kw_void:
|
||||
|
|
|
@ -368,6 +368,7 @@ bool Declarator::isDeclarationOfFunction() const {
|
|||
case TST_unspecified:
|
||||
case TST_void:
|
||||
case TST_wchar:
|
||||
case TST_BFloat16:
|
||||
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
return false;
|
||||
|
@ -566,6 +567,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
|
|||
case DeclSpec::TST_underlyingType: return "__underlying_type";
|
||||
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
|
||||
case DeclSpec::TST_atomic: return "_Atomic";
|
||||
case DeclSpec::TST_BFloat16: return "__bf16";
|
||||
#define GENERIC_IMAGE_TYPE(ImgType, Id) \
|
||||
case DeclSpec::TST_##ImgType##_t: \
|
||||
return #ImgType "_t";
|
||||
|
|
|
@ -2789,6 +2789,20 @@ void CastOperation::CheckCStyleCast() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Can't cast to or from bfloat
|
||||
if (DestType->isBFloat16Type() && !SrcType->isBFloat16Type()) {
|
||||
Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_to_bfloat16)
|
||||
<< SrcExpr.get()->getSourceRange();
|
||||
SrcExpr = ExprError();
|
||||
return;
|
||||
}
|
||||
if (SrcType->isBFloat16Type() && !DestType->isBFloat16Type()) {
|
||||
Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_from_bfloat16)
|
||||
<< SrcExpr.get()->getSourceRange();
|
||||
SrcExpr = ExprError();
|
||||
return;
|
||||
}
|
||||
|
||||
// If either type is a pointer, the other type has to be either an
|
||||
// integer or a pointer.
|
||||
if (!DestType->isArithmeticType()) {
|
||||
|
|
|
@ -1961,6 +1961,9 @@ static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) {
|
|||
case NeonTypeFlags::Float64:
|
||||
assert(!shift && "cannot shift float types!");
|
||||
return (1 << IsQuad) - 1;
|
||||
case NeonTypeFlags::BFloat16:
|
||||
assert(!shift && "cannot shift float types!");
|
||||
return (4 << IsQuad) - 1;
|
||||
}
|
||||
llvm_unreachable("Invalid NeonTypeFlag!");
|
||||
}
|
||||
|
@ -2000,6 +2003,8 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
|
|||
return Context.FloatTy;
|
||||
case NeonTypeFlags::Float64:
|
||||
return Context.DoubleTy;
|
||||
case NeonTypeFlags::BFloat16:
|
||||
return Context.BFloat16Ty;
|
||||
}
|
||||
llvm_unreachable("Invalid NeonTypeFlag!");
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
|
|||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw___bf16:
|
||||
case tok::kw__Float16:
|
||||
case tok::kw___float128:
|
||||
case tok::kw_wchar_t:
|
||||
|
|
|
@ -8133,6 +8133,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
|
|||
return ResTy;
|
||||
}
|
||||
|
||||
// And if they're both bfloat (which isn't arithmetic), that's fine too.
|
||||
if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) {
|
||||
return LHSTy;
|
||||
}
|
||||
|
||||
// If both operands are the same structure or union type, the result is that
|
||||
// type.
|
||||
if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
|
||||
|
|
|
@ -1870,6 +1870,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
|||
// FIXME: disable conversions between long double and __float128 if
|
||||
// their representation is different until there is back end support
|
||||
// We of course allow this conversion if long double is really double.
|
||||
|
||||
// Conversions between bfloat and other floats are not permitted.
|
||||
if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty)
|
||||
return false;
|
||||
if (&S.Context.getFloatTypeSemantics(FromType) !=
|
||||
&S.Context.getFloatTypeSemantics(ToType)) {
|
||||
bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty &&
|
||||
|
@ -1888,6 +1892,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
|||
ToType->isIntegralType(S.Context)) ||
|
||||
(FromType->isIntegralOrUnscopedEnumerationType() &&
|
||||
ToType->isRealFloatingType())) {
|
||||
// Conversions between bfloat and int are not permitted.
|
||||
if (FromType->isBFloat16Type() || ToType->isBFloat16Type())
|
||||
return false;
|
||||
|
||||
// Floating-integral conversions (C++ 4.9).
|
||||
SCS.Second = ICK_Floating_Integral;
|
||||
FromType = ToType.getUnqualifiedType();
|
||||
|
|
|
@ -881,6 +881,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
|
|||
case TST_auto:
|
||||
case TST_auto_type:
|
||||
case TST_decltype_auto:
|
||||
case TST_BFloat16:
|
||||
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
case TST_unknown_anytype:
|
||||
|
|
|
@ -1521,6 +1521,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
|||
Result = Context.Float16Ty;
|
||||
break;
|
||||
case DeclSpec::TST_half: Result = Context.HalfTy; break;
|
||||
case DeclSpec::TST_BFloat16:
|
||||
if (!S.Context.getTargetInfo().hasBFloat16Type())
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
|
||||
<< "__bf16";
|
||||
Result = Context.BFloat16Ty;
|
||||
break;
|
||||
case DeclSpec::TST_float: Result = Context.FloatTy; break;
|
||||
case DeclSpec::TST_double:
|
||||
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
|
||||
|
@ -7673,7 +7679,8 @@ static bool isPermittedNeonBaseType(QualType &Ty,
|
|||
BTy->getKind() == BuiltinType::LongLong ||
|
||||
BTy->getKind() == BuiltinType::ULongLong ||
|
||||
BTy->getKind() == BuiltinType::Float ||
|
||||
BTy->getKind() == BuiltinType::Half;
|
||||
BTy->getKind() == BuiltinType::Half ||
|
||||
BTy->getKind() == BuiltinType::BFloat16;
|
||||
}
|
||||
|
||||
/// HandleNeonVectorTypeAttr - The "neon_vector_type" and
|
||||
|
|
|
@ -252,6 +252,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
|
|||
case BuiltinType::OMPIterator:
|
||||
ID = PREDEF_TYPE_OMP_ITERATOR;
|
||||
break;
|
||||
case BuiltinType::BFloat16:
|
||||
ID = PREDEF_TYPE_BFLOAT16_ID;
|
||||
break;
|
||||
}
|
||||
|
||||
return TypeIdx(ID);
|
||||
|
|
|
@ -6844,6 +6844,9 @@ QualType ASTReader::GetType(TypeID ID) {
|
|||
case PREDEF_TYPE_INT128_ID:
|
||||
T = Context.Int128Ty;
|
||||
break;
|
||||
case PREDEF_TYPE_BFLOAT16_ID:
|
||||
T = Context.BFloat16Ty;
|
||||
break;
|
||||
case PREDEF_TYPE_HALF_ID:
|
||||
T = Context.HalfTy;
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clang_cc1 -triple armv8.6a-arm-none-eabi -target-abi aapcs -mfloat-abi hard -target-feature +bf16 -target-feature +neon -emit-llvm -O2 -o - %s | opt -S -mem2reg -sroa | FileCheck %s --check-prefix=CHECK32-HARD
|
||||
// RUN: %clang_cc1 -triple aarch64-arm-none-eabi -target-abi aapcs -mfloat-abi hard -target-feature +bf16 -target-feature +neon -emit-llvm -O2 -o - %s | opt -S -mem2reg -sroa | FileCheck %s --check-prefix=CHECK64-HARD
|
||||
// RUN: %clang_cc1 -triple armv8.6a-arm-none-eabi -target-abi aapcs -mfloat-abi softfp -target-feature +bf16 -target-feature +neon -emit-llvm -O2 -o - %s | opt -S -mem2reg -sroa | FileCheck %s --check-prefix=CHECK32-SOFTFP
|
||||
// RUN: %clang_cc1 -triple aarch64-arm-none-eabi -target-abi aapcs -mfloat-abi softfp -target-feature +bf16 -target-feature +neon -emit-llvm -O2 -o - %s | opt -S -mem2reg -sroa | FileCheck %s --check-prefix=CHECK64-SOFTFP
|
||||
|
||||
// function return types
|
||||
__bf16 test_ret_bf16(__bf16 v) {
|
||||
return v;
|
||||
}
|
||||
// CHECK32-HARD: define arm_aapcs_vfpcc bfloat @test_ret_bf16(bfloat returned %v) {{.*}} {
|
||||
// CHECK32-HARD: ret bfloat %v
|
||||
// CHECK64-HARD: define bfloat @test_ret_bf16(bfloat returned %v) {{.*}} {
|
||||
// CHECK64-HARD: ret bfloat %v
|
||||
// CHECK32-SOFTFP: define i32 @test_ret_bf16(i32 [[V0:.*]]) {{.*}} {
|
||||
// CHECK32-SOFTFP: %tmp2.0.insert.ext = and i32 [[V0]], 65535
|
||||
// CHECK32-SOFTFP: ret i32 %tmp2.0.insert.ext
|
||||
// CHECK64-SOFTFP: define bfloat @test_ret_bf16(bfloat returned %v) {{.*}} {
|
||||
// CHECK64-SOFTFP: ret bfloat %v
|
|
@ -0,0 +1,4 @@
|
|||
// RUN: not %clang -target arm-arm-eabi -march=armv8-a+bf16 -mfloat-abi=soft -c %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: error: __bf16 is not supported on this target
|
||||
extern __bf16 var;
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: %clang_cc1 -triple aarch64-arm-none-eabi -target-feature +bf16 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK64
|
||||
// RUN: %clang_cc1 -triple arm-arm-none-eabi -target-feature +bf16 -mfloat-abi hard -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK32-HARD
|
||||
// RUN: %clang_cc1 -triple arm-arm-none-eabi -target-feature +bf16 -mfloat-abi softfp -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK32-SOFTFP
|
||||
|
||||
// CHECK64: define {{.*}}void @_Z3foou6__bf16(bfloat %b)
|
||||
// CHECK32-HARD: define {{.*}}void @_Z3foou6__bf16(bfloat %b)
|
||||
// CHECK32-SOFTFP: define {{.*}}void @_Z3foou6__bf16(i32 %b.coerce)
|
||||
void foo(__bf16 b) {}
|
|
@ -0,0 +1,71 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64 -target-feature +bf16 %s
|
||||
|
||||
__bf16 test_cast_from_float(float in) {
|
||||
return (__bf16)in; // expected-error {{cannot type-cast to __bf16}}
|
||||
}
|
||||
|
||||
__bf16 test_cast_from_float_literal(void) {
|
||||
return (__bf16)1.0f; // expected-error {{cannot type-cast to __bf16}}
|
||||
}
|
||||
|
||||
__bf16 test_cast_from_int(int in) {
|
||||
return (__bf16)in; // expected-error {{cannot type-cast to __bf16}}
|
||||
}
|
||||
|
||||
__bf16 test_cast_from_int_literal(void) {
|
||||
return (__bf16)1; // expected-error {{cannot type-cast to __bf16}}
|
||||
}
|
||||
|
||||
__bf16 test_cast_bfloat(__bf16 in) {
|
||||
return (__bf16)in; // this one should work
|
||||
}
|
||||
|
||||
float test_cast_to_float(__bf16 in) {
|
||||
return (float)in; // expected-error {{cannot type-cast from __bf16}}
|
||||
}
|
||||
|
||||
int test_cast_to_int(__bf16 in) {
|
||||
return (int)in; // expected-error {{cannot type-cast from __bf16}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_float(float in) {
|
||||
return in; // expected-error {{returning 'float' from a function with incompatible result type '__bf16'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_float_literal(void) {
|
||||
return 1.0f; // expected-error {{returning 'float' from a function with incompatible result type '__bf16'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_int(int in) {
|
||||
return in; // expected-error {{returning 'int' from a function with incompatible result type '__bf16'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_int_literal(void) {
|
||||
return 1; // expected-error {{returning 'int' from a function with incompatible result type '__bf16'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_bfloat(__bf16 in) {
|
||||
return in; // this one should work
|
||||
}
|
||||
|
||||
float test_implicit_to_float(__bf16 in) {
|
||||
return in; // expected-error {{returning '__bf16' from a function with incompatible result type 'float'}}
|
||||
}
|
||||
|
||||
int test_implicit_to_int(__bf16 in) {
|
||||
return in; // expected-error {{returning '__bf16' from a function with incompatible result type 'int'}}
|
||||
}
|
||||
|
||||
__bf16 test_cond(__bf16 a, __bf16 b, _Bool which) {
|
||||
// Conditional operator _should_ be supported, without nonsense
|
||||
// complaints like 'types __bf16 and __bf16 are not compatible'
|
||||
return which ? a : b;
|
||||
}
|
||||
|
||||
__bf16 test_cond_float(__bf16 a, __bf16 b, _Bool which) {
|
||||
return which ? a : 1.0f; // expected-error {{incompatible operand types ('__bf16' and 'float')}}
|
||||
}
|
||||
|
||||
__bf16 test_cond_int(__bf16 a, __bf16 b, _Bool which) {
|
||||
return which ? a : 1; // expected-error {{incompatible operand types ('__bf16' and 'int')}}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64 -target-feature +bf16 %s
|
||||
|
||||
__bf16 test_static_cast_from_float(float in) {
|
||||
return static_cast<__bf16>(in); // expected-error {{static_cast from 'float' to '__bf16' is not allowed}}
|
||||
}
|
||||
|
||||
__bf16 test_static_cast_from_float_literal(void) {
|
||||
return static_cast<__bf16>(1.0f); // expected-error {{static_cast from 'float' to '__bf16' is not allowed}}
|
||||
}
|
||||
|
||||
__bf16 test_static_cast_from_int(int in) {
|
||||
return static_cast<__bf16>(in); // expected-error {{static_cast from 'int' to '__bf16' is not allowed}}
|
||||
}
|
||||
|
||||
__bf16 test_static_cast_from_int_literal(void) {
|
||||
return static_cast<__bf16>(1); // expected-error {{static_cast from 'int' to '__bf16' is not allowed}}
|
||||
}
|
||||
|
||||
__bf16 test_static_cast_bfloat(__bf16 in) {
|
||||
return static_cast<__bf16>(in); // this one should work
|
||||
}
|
||||
|
||||
float test_static_cast_to_float(__bf16 in) {
|
||||
return static_cast<float>(in); // expected-error {{static_cast from '__bf16' to 'float' is not allowed}}
|
||||
}
|
||||
|
||||
int test_static_cast_to_int(__bf16 in) {
|
||||
return static_cast<int>(in); // expected-error {{static_cast from '__bf16' to 'int' is not allowed}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_float(float in) {
|
||||
return in; // expected-error {{cannot initialize return object of type '__bf16' with an lvalue of type 'float'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_float_literal() {
|
||||
return 1.0f; // expected-error {{cannot initialize return object of type '__bf16' with an rvalue of type 'float'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_int(int in) {
|
||||
return in; // expected-error {{cannot initialize return object of type '__bf16' with an lvalue of type 'int'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_from_int_literal() {
|
||||
return 1; // expected-error {{cannot initialize return object of type '__bf16' with an rvalue of type 'int'}}
|
||||
}
|
||||
|
||||
__bf16 test_implicit_bfloat(__bf16 in) {
|
||||
return in; // this one should work
|
||||
}
|
||||
|
||||
float test_implicit_to_float(__bf16 in) {
|
||||
return in; // expected-error {{cannot initialize return object of type 'float' with an lvalue of type '__bf16'}}
|
||||
}
|
||||
|
||||
int test_implicit_to_int(__bf16 in) {
|
||||
return in; // expected-error {{cannot initialize return object of type 'int' with an lvalue of type '__bf16'}}
|
||||
}
|
||||
|
||||
__bf16 test_cond(__bf16 a, __bf16 b, bool which) {
|
||||
// Conditional operator _should_ be supported, without nonsense
|
||||
// complaints like 'types __bf16 and __bf16 are not compatible'
|
||||
return which ? a : b;
|
||||
}
|
||||
|
||||
__bf16 test_cond_float(__bf16 a, __bf16 b, bool which) {
|
||||
return which ? a : 1.0f; // expected-error {{incompatible operand types ('__bf16' and 'float')}}
|
||||
}
|
||||
|
||||
__bf16 test_cond_int(__bf16 a, __bf16 b, bool which) {
|
||||
return which ? a : 1; // expected-error {{incompatible operand types ('__bf16' and 'int')}}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 \
|
||||
// RUN: -triple aarch64-arm-none-eabi -target-cpu cortex-a75 \
|
||||
// RUN: -target-feature +bf16 -target-feature +neon %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 \
|
||||
// RUN: -triple arm-arm-none-eabi -target-cpu cortex-a53 \
|
||||
// RUN: -target-feature +bf16 -target-feature +neon %s
|
||||
|
||||
void test(bool b) {
|
||||
__bf16 bf16;
|
||||
|
||||
bf16 + bf16; // expected-error {{invalid operands to binary expression ('__bf16' and '__bf16')}}
|
||||
bf16 - bf16; // expected-error {{invalid operands to binary expression ('__bf16' and '__bf16')}}
|
||||
bf16 * bf16; // expected-error {{invalid operands to binary expression ('__bf16' and '__bf16')}}
|
||||
bf16 / bf16; // expected-error {{invalid operands to binary expression ('__bf16' and '__bf16')}}
|
||||
|
||||
__fp16 fp16;
|
||||
|
||||
bf16 + fp16; // expected-error {{invalid operands to binary expression ('__bf16' and '__fp16')}}
|
||||
fp16 + bf16; // expected-error {{invalid operands to binary expression ('__fp16' and '__bf16')}}
|
||||
bf16 - fp16; // expected-error {{invalid operands to binary expression ('__bf16' and '__fp16')}}
|
||||
fp16 - bf16; // expected-error {{invalid operands to binary expression ('__fp16' and '__bf16')}}
|
||||
bf16 * fp16; // expected-error {{invalid operands to binary expression ('__bf16' and '__fp16')}}
|
||||
fp16 * bf16; // expected-error {{invalid operands to binary expression ('__fp16' and '__bf16')}}
|
||||
bf16 / fp16; // expected-error {{invalid operands to binary expression ('__bf16' and '__fp16')}}
|
||||
fp16 / bf16; // expected-error {{invalid operands to binary expression ('__fp16' and '__bf16')}}
|
||||
bf16 = fp16; // expected-error {{assigning to '__bf16' from incompatible type '__fp16'}}
|
||||
fp16 = bf16; // expected-error {{assigning to '__fp16' from incompatible type '__bf16'}}
|
||||
bf16 + (b ? fp16 : bf16); // expected-error {{incompatible operand types ('__fp16' and '__bf16')}}
|
||||
}
|
|
@ -608,6 +608,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
|
|||
TKIND(Elaborated);
|
||||
TKIND(Pipe);
|
||||
TKIND(Attributed);
|
||||
TKIND(BFloat16);
|
||||
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id);
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
#undef IMAGE_TYPE
|
||||
|
|
Loading…
Reference in New Issue