diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -514,8 +514,8 @@ 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 @@ -527,6 +527,10 @@ ``_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) + ``__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``. diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3253,8 +3253,9 @@ 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, diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -964,6 +964,7 @@ 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; diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -212,6 +212,9 @@ // '_Float16' FLOATING_TYPE(Float16, HalfTy) +// '__bf16' +FLOATING_TYPE(BFloat16, BFloat16Ty) + // '__float128' FLOATING_TYPE(Float128, Float128Ty) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2008,6 +2008,7 @@ 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) @@ -6926,6 +6927,10 @@ return isSpecificBuiltinType(BuiltinType::Float16); } +inline bool Type::isBFloat16Type() const { + return isSpecificBuiltinType(BuiltinType::BFloat16); +} + inline bool Type::isFloat128Type() const { return isSpecificBuiltinType(BuiltinType::Float128); } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8115,6 +8115,8 @@ InGroup, 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< diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -72,6 +72,7 @@ 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, diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -142,7 +142,8 @@ Poly128, Float16, Float32, - Float64 + Float64, + BFloat16 }; NeonTypeFlags(unsigned F) : Flags(F) {} diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -59,6 +59,7 @@ 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 @@ 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 @@ // LLVM IR type. bool HasFloat128; bool HasFloat16; + bool HasBFloat16; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; unsigned short SimdDefaultAlign; @@ -562,6 +564,9 @@ /// 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; } @@ -610,6 +615,11 @@ 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; } @@ -637,6 +647,11 @@ /// 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; } diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -591,6 +591,7 @@ // ARM NEON extensions. ALIAS("__fp16", half , KEYALL) +KEYWORD(__bf16 , KEYALL) // OpenCL Extension. KEYWORD(half , HALFSUPPORT) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -281,6 +281,7 @@ 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; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1057,6 +1057,9 @@ /// The placeholder type for OpenMP iterator expression. PREDEF_TYPE_OMP_ITERATOR = 71, + /// \brief The '__bf16' type + PREDEF_TYPE_BFLOAT16_ID = 72, + /// OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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 @@ -1446,6 +1446,8 @@ // 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; @@ -1649,6 +1651,8 @@ switch (T->castAs()->getKind()) { default: llvm_unreachable("Not a floating point type!"); + case BuiltinType::BFloat16: + return Target->getBFloat16Format(); case BuiltinType::Float16: case BuiltinType::Half: return Target->getHalfFormat(); @@ -2043,6 +2047,10 @@ 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 || @@ -5982,6 +5990,7 @@ case BuiltinType::Double: return DoubleRank; case BuiltinType::LongDouble: return LongDoubleRank; case BuiltinType::Float128: return Float128Rank; + case BuiltinType::BFloat16: return BFloat16Rank; } } @@ -5994,6 +6003,7 @@ 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; @@ -6006,6 +6016,7 @@ 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; @@ -6983,6 +6994,7 @@ case BuiltinType::LongDouble: return 'D'; case BuiltinType::NullPtr: return '*'; // like char* + case BuiltinType::BFloat16: case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::Half: @@ -9890,6 +9902,11 @@ // 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'!"); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2764,6 +2764,11 @@ 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 @@ 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 @@ return "Float32"; case BuiltinType::Double: return "Float64"; + case BuiltinType::BFloat16: + return "BFloat16"; default: llvm_unreachable("Unexpected vector element base type"); } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -2114,6 +2114,7 @@ case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: + case BuiltinType::BFloat16: case BuiltinType::Float128: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -485,6 +485,7 @@ case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: + case BuiltinType::BFloat16: break; } diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -752,6 +752,7 @@ case BuiltinType::UInt128: case BuiltinType::Int128: case BuiltinType::Half: + case BuiltinType::BFloat16: case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::ShortAccum: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2137,7 +2137,8 @@ bool Type::isArithmeticType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::Float128; + BT->getKind() <= BuiltinType::Float128 && + BT->getKind() != BuiltinType::BFloat16; if (const auto *ET = dyn_cast(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 @@ return "unsigned __int128"; case Half: return Policy.Half ? "half" : "__fp16"; + case BFloat16: + return "__bf16"; case Float: return "float"; case Double: diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -375,6 +375,7 @@ 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. diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -36,6 +36,7 @@ HasLegalHalfType = false; HasFloat128 = false; HasFloat16 = false; + HasBFloat16 = false; PointerWidth = PointerAlign = 32; BoolWidth = BoolAlign = 8; IntWidth = IntAlign = 32; diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -119,6 +119,7 @@ int getEHDataRegisterNumber(unsigned RegNo) const override; + const char *getBFloat16Mangling() const override { return "u6__bf16"; }; bool hasInt128Type() const override; bool hasExtIntType() const override { return true; } diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -70,6 +70,9 @@ 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 @@ HasMTE = false; HasTME = false; HasMatMul = false; + HasBFloat16 = false; ArchKind = llvm::AArch64::ArchKind::ARMV8A; for (const auto &Feature : Features) { @@ -397,6 +401,8 @@ HasTME = true; if (Feature == "+i8mm") HasMatMul = true; + if (Feature == "+bf16") + HasBFloat16 = true; } setDataLayout(); diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -184,6 +184,8 @@ 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 { diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -25,6 +25,9 @@ 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 @@ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; else DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; + BFloat16Width = BFloat16Align = 16; + BFloat16Format = &llvm::APFloat::BFloat(); WCharType = SignedInt; @@ -428,6 +433,7 @@ 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 @@ Feature <= "+cdecp7") { unsigned Coproc = Feature.back() - '0'; ARMCDECoprocMask |= (1U << Coproc); + } else if (Feature == "+bf16") { + HasBFloat16 = true; } } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4479,7 +4479,8 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF, NeonTypeFlags TypeFlags, bool HasLegalHalfType=true, - bool V1Ty=false) { + bool V1Ty=false, + bool HasBFloat16Type=true) { int IsQuad = TypeFlags.isQuad(); switch (TypeFlags.getEltType()) { case NeonTypeFlags::Int8: @@ -4488,6 +4489,11 @@ case NeonTypeFlags::Int16: case NeonTypeFlags::Poly16: return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); + case NeonTypeFlags::BFloat16: + if (HasBFloat16Type) + return llvm::VectorType::get(CGF->BFloatTy, V1Ty ? 1 : (4 << IsQuad)); + else + return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); case NeonTypeFlags::Float16: if (HasLegalHalfType) return llvm::VectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad)); @@ -5503,8 +5509,9 @@ bool Usgn = Type.isUnsigned(); bool Quad = Type.isQuad(); const bool HasLegalHalfType = getTarget().hasLegalHalfType(); + const bool HasBFloat16Type = getTarget().hasBFloat16Type(); - llvm::VectorType *VTy = GetNeonType(this, Type, HasLegalHalfType); + llvm::VectorType *VTy = GetNeonType(this, Type, HasLegalHalfType, false, HasBFloat16Type); llvm::Type *Ty = VTy; if (!Ty) return nullptr; @@ -6973,7 +6980,9 @@ bool rightShift = false; llvm::VectorType *VTy = GetNeonType(this, Type, - getTarget().hasLegalHalfType()); + getTarget().hasLegalHalfType(), + false, + getTarget().hasBFloat16Type()); llvm::Type *Ty = VTy; if (!Ty) return nullptr; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -768,6 +768,7 @@ 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, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -112,6 +112,7 @@ 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); diff --git a/clang/lib/CodeGen/CodeGenTypeCache.h b/clang/lib/CodeGen/CodeGenTypeCache.h --- a/clang/lib/CodeGen/CodeGenTypeCache.h +++ b/clang/lib/CodeGen/CodeGenTypeCache.h @@ -35,8 +35,8 @@ /// 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; diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -300,6 +300,8 @@ 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 @@ Context.getLangOpts().NativeHalfType || !Context.getTargetInfo().useFP16ConversionIntrinsics()); break; + case BuiltinType::BFloat16: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -3027,6 +3027,7 @@ case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: + case BuiltinType::BFloat16: return false; case BuiltinType::Dependent: diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5979,11 +5979,14 @@ 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 { @@ -6253,9 +6256,9 @@ 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 ? @@ -6264,6 +6267,13 @@ return ABIArgInfo::getDirect(ResType); } + // __bf16 get 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()) { @@ -6457,10 +6467,13 @@ // 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() && + // 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); } @@ -6475,6 +6488,15 @@ 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()) @@ -6561,12 +6583,17 @@ /// isIllegalVector - check whether Ty is an illegal vector type. bool ARMABIInfo::isIllegalVectorType(QualType Ty) const { if (const VectorType *VT = Ty->getAs ()) { - // 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 @@ -6618,6 +6645,7 @@ } else { if (const VectorType *VT = Ty->getAs()) return (VT->getElementType()->isFloat16Type() || + VT->getElementType()->isBFloat16Type() || VT->getElementType()->isHalfType()); return false; } diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -50,6 +50,7 @@ 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: diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -753,6 +753,7 @@ case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: + case BuiltinType::BFloat16: IgnoreResults = true; return; case BuiltinType::ObjCId: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3842,6 +3842,10 @@ 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 @@ 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 @@ 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 @@ 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: diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1499,6 +1499,7 @@ 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: diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -2201,6 +2201,9 @@ 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; diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1631,6 +1631,7 @@ 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: @@ -1744,6 +1745,7 @@ 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: diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -368,6 +368,7 @@ 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 @@ 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"; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2786,6 +2786,20 @@ 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()) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1961,6 +1961,9 @@ 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 @@ return Context.FloatTy; case NeonTypeFlags::Float64: return Context.DoubleTy; + case NeonTypeFlags::BFloat16: + return Context.BFloat16Ty; } llvm_unreachable("Invalid NeonTypeFlag!"); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -138,6 +138,7 @@ 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: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7996,6 +7996,11 @@ 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()) { // C99 6.5.15p3 diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1870,6 +1870,10 @@ // 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 @@ 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(); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -881,6 +881,7 @@ 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: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1521,6 +1521,12 @@ 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) @@ -7672,7 +7678,8 @@ 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 diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -249,6 +249,9 @@ case BuiltinType::OMPIterator: ID = PREDEF_TYPE_OMP_ITERATOR; break; + case BuiltinType::BFloat16: + ID = PREDEF_TYPE_BFLOAT16_ID; + break; } return TypeIdx(ID); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6844,6 +6844,9 @@ 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; diff --git a/clang/test/CodeGen/arm-bf16-params-returns.c b/clang/test/CodeGen/arm-bf16-params-returns.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm-bf16-params-returns.c @@ -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 diff --git a/clang/test/CodeGen/arm-mangle-16bit-float.cpp b/clang/test/CodeGen/arm-mangle-16bit-float.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm-mangle-16bit-float.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple aarch64-arm-none-eabi -fallow-half-arguments-and-returns -target-feature +fullfp16 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK64 +// RUN: %clang_cc1 -triple arm-arm-none-eabi -fallow-half-arguments-and-returns -target-feature +fullfp16 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK32 + +// CHECK64: define {{.*}}void @_Z3barDh(half %b) +// CHECK32: define {{.*}}void @_Z3barDh(i32 %b.coerce) +void bar(__fp16 b) {} diff --git a/clang/test/CodeGen/arm-mangle-bf16.cpp b/clang/test/CodeGen/arm-mangle-bf16.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm-mangle-bf16.cpp @@ -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) {} diff --git a/clang/test/Sema/arm-bf16-forbidden-ops.c b/clang/test/Sema/arm-bf16-forbidden-ops.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arm-bf16-forbidden-ops.c @@ -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')}} +} diff --git a/clang/test/Sema/arm-bf16-forbidden-ops.cpp b/clang/test/Sema/arm-bf16-forbidden-ops.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arm-bf16-forbidden-ops.cpp @@ -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(in); // expected-error {{static_cast from '__bf16' to 'float' is not allowed}} +} + +int test_static_cast_to_int(__bf16 in) { + return static_cast(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')}} +} diff --git a/clang/test/Sema/arm-bfloat.cpp b/clang/test/Sema/arm-bfloat.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arm-bfloat.cpp @@ -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')}} +} diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -608,6 +608,7 @@ 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